IDEA-197739 -introducing maven online autocompletion without using indices

This commit is contained in:
Alexander Bubenchikov
2019-04-02 16:29:38 +03:00
parent 1d32b7440d
commit 3cd2fe4a44
47 changed files with 1953 additions and 1142 deletions
@@ -32,7 +32,7 @@ import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.indices.MavenIndex;
import org.jetbrains.idea.maven.indices.MavenSearchIndex;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenRemoteRepository;
import org.jetbrains.plugins.gradle.util.GradleConstants;
@@ -127,7 +127,7 @@ class ImportMavenRepositoriesTask {
.filter(index -> index.getUpdateTimestamp() == -1 &&
index.getFailureMessage() == null &&
MavenRepositoriesHolder.getInstance(myProject).contains(index.getRepositoryPathOrUrl()))
.map(MavenIndex::getRepositoryPathOrUrl)
.map(MavenSearchIndex::getRepositoryPathOrUrl)
.collect(Collectors.toList());
MavenRepositoriesHolder.getInstance(myProject).updateNotIndexedUrls(repositoriesWithEmptyIndex);
});
@@ -17,6 +17,7 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Key;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.indices.MavenSearchIndex;
import org.jetbrains.idea.maven.indices.MavenIndex;
import org.jetbrains.idea.maven.indices.MavenIndicesManager;
import org.jetbrains.idea.maven.model.MavenRemoteRepository;
@@ -69,7 +70,7 @@ public class MavenRepositoriesHolder {
if (notificationManager.isNotificationActive(NOTIFICATION_KEY)) return;
final MavenIndicesManager indicesManager = MavenIndicesManager.getInstance();
for (MavenIndex index : indicesManager.getIndices()) {
for (MavenSearchIndex index : indicesManager.getIndices()) {
if (indicesManager.getUpdatingState(index) != IDLE) return;
}
@@ -87,7 +88,7 @@ public class MavenRepositoriesHolder {
ContainerUtil.filter(indicesManager.getIndices(), index -> isNotIndexed(index.getRepositoryPathOrUrl()));
indicesManager.scheduleUpdate(myProject, notIndexed).onSuccess(aVoid -> {
if (myNotIndexedUrls.isEmpty()) return;
for (MavenIndex index : notIndexed) {
for (MavenSearchIndex index : notIndexed) {
if (index.getUpdateTimestamp() != -1 || index.getFailureMessage() != null) {
myNotIndexedUrls.remove(index.getRepositoryPathOrUrl());
}
@@ -4,10 +4,10 @@ package org.jetbrains.idea.maven.dom.converters;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.completion.OffsetKey;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.codeInsight.template.TemplateManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
@@ -23,10 +23,12 @@ import org.jetbrains.idea.maven.dom.model.MavenDomDependency;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.project.MavenProject;
import java.util.Collections;
import java.util.Set;
import java.util.stream.Collectors;
public class MavenArtifactCoordinatesArtifactIdConverter extends MavenArtifactCoordinatesConverter {
@Override
@@ -58,9 +60,9 @@ public class MavenArtifactCoordinatesArtifactIdConverter extends MavenArtifactCo
}
@Override
protected Set<String> doGetVariants(MavenId id, MavenProjectIndicesManager manager) {
protected Set<String> doGetVariants(MavenId id, DependencySearchService searchService) {
if (StringUtil.isEmptyOrSpaces(id.getGroupId())) return Collections.emptySet();
return manager.getArtifactIds(id.getGroupId());
return searchService.findArtifactCandidates(id).stream().map(s -> s.getArtifactId()).collect(Collectors.toSet());
}
private static class MavenArtifactInsertHandler implements InsertHandler<LookupElement> {
@@ -76,7 +78,7 @@ public class MavenArtifactCoordinatesArtifactIdConverter extends MavenArtifactCo
context.commitDocument();
PsiFile contextFile = context.getFile();
if(!(contextFile instanceof XmlFile)) return;
if (!(contextFile instanceof XmlFile)) return;
XmlFile xmlFile = (XmlFile)contextFile;
@@ -91,50 +93,27 @@ public class MavenArtifactCoordinatesArtifactIdConverter extends MavenArtifactCo
MavenDomDependency dependency = (MavenDomDependency)domElement;
String artifactId = item.getLookupString();
MavenId id = new MavenId(item.getLookupString());
String artifactId = id.getArtifactId();
String groupId = dependency.getGroupId().getStringValue();
OffsetKey startRef = context.trackOffset(context.getStartOffset(), false);
int len = context.getTailOffset() - context.getStartOffset();
if (StringUtil.isEmpty(groupId)) {
String g = getUniqueGroupIdOrNull(context.getProject(), artifactId);
if (g != null) {
dependency.getGroupId().setStringValue(g);
groupId = g;
}
else {
if (groupId == null) {
dependency.getGroupId().setStringValue("");
}
XmlTag groupIdTag = dependency.getGroupId().getXmlTag();
context.getEditor().getCaretModel().moveToOffset(groupIdTag.getValue().getTextRange().getStartOffset());
MavenDependencyCompletionUtil.invokeCompletion(context, CompletionType.SMART);
return;
groupId = id.getGroupId();
if (StringUtil.isEmpty(groupId)) {
dependency.getGroupId().setStringValue("");
}
XmlTag groupIdTag = dependency.getGroupId().getXmlTag();
context.getEditor().getCaretModel().moveToOffset(groupIdTag.getValue().getTextRange().getStartOffset());
MavenDependencyCompletionUtil.invokeCompletion(context, CompletionType.SMART);
return;
}
int offset = context.getOffset(startRef);
context.getDocument().replaceString(offset, offset + len, artifactId);
context.commitDocument();
MavenDependencyCompletionUtil.addTypeAndClassifierAndVersion(context, dependency, groupId, artifactId);
}
private static String getUniqueGroupIdOrNull(@NotNull Project project, @NotNull String artifactId) {
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(project);
String res = null;
for (String groupId : manager.getGroupIds()) {
if (manager.getArtifactIds(groupId).contains(artifactId)) {
if (res == null) {
res = groupId;
}
else {
return null; // There are more then one appropriate groupId.
}
}
}
return res;
}
}
}
@@ -26,7 +26,10 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiManager;
import com.intellij.util.ArrayUtil;
import com.intellij.util.xml.*;
import com.intellij.util.xml.ConvertContext;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.GenericDomValue;
import com.intellij.util.xml.ResolvingConverter;
import com.intellij.util.xml.impl.GenericDomValueReference;
import gnu.trove.THashSet;
import org.jetbrains.annotations.NonNls;
@@ -40,6 +43,7 @@ import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.model.MavenPlugin;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
import org.jetbrains.idea.maven.utils.MavenArtifactUtil;
@@ -69,15 +73,15 @@ public abstract class MavenArtifactCoordinatesConverter extends ResolvingConvert
@Override
@NotNull
public Collection<String> getVariants(ConvertContext context) {
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(context.getProject());
DependencySearchService searchService = MavenProjectIndicesManager.getInstance(context.getProject()).getSearchService();
MavenId id = MavenArtifactCoordinatesHelper.getId(context);
MavenDomShortArtifactCoordinates coordinates = MavenArtifactCoordinatesHelper.getCoordinates(context);
return selectStrategy(context).getVariants(id, manager, coordinates);
return selectStrategy(context).getVariants(id, searchService, coordinates);
}
protected abstract Set<String> doGetVariants(MavenId id, MavenProjectIndicesManager manager);
protected abstract Set<String> doGetVariants(MavenId id, DependencySearchService searchService);
@Override
public PsiElement resolve(String o, ConvertContext context) {
@@ -94,7 +98,14 @@ public abstract class MavenArtifactCoordinatesConverter extends ResolvingConvert
@Override
public LocalQuickFix[] getQuickFixes(ConvertContext context) {
return ArrayUtil.append(super.getQuickFixes(context), new MyUpdateIndicesFix());
MavenId id = MavenArtifactCoordinatesHelper.getId(context);
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(context.getProject());
if (manager.hasOfflineIndexes()) {
return ArrayUtil.append(super.getQuickFixes(context), new MyUpdateIndicesFix());
}
else {
return super.getQuickFixes(context);
}
}
@Override
@@ -191,8 +202,8 @@ public abstract class MavenArtifactCoordinatesConverter extends ResolvingConvert
return doIsValid(id, manager, context) || resolveBySpecifiedPath() != null;
}
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
return doGetVariants(id, manager);
public Set<String> getVariants(MavenId id, DependencySearchService searchService, MavenDomShortArtifactCoordinates coordinates) {
return doGetVariants(id, searchService);
}
public PsiFile resolve(MavenId id, ConvertContext context) {
@@ -318,21 +329,6 @@ public abstract class MavenArtifactCoordinatesConverter extends ResolvingConvert
public PsiFile resolveBySpecifiedPath() {
return myDependency.getSystemPath().getValue();
}
@Override
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
if (StringUtil.isEmpty(id.getGroupId())) {
Set<String> result = new THashSet<>();
for (String each : manager.getGroupIds()) {
id = new MavenId(each, id.getArtifactId(), id.getVersion());
result.addAll(super.getVariants(id, manager, coordinates));
}
return result;
}
return super.getVariants(id, manager, coordinates);
}
}
private class ExclusionStrategy extends ConverterStrategy {
@@ -372,25 +368,17 @@ public abstract class MavenArtifactCoordinatesConverter extends ResolvingConvert
}
@Override
public Set<String> getVariants(MavenId id, MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
public Set<String> getVariants(MavenId id, DependencySearchService searchService, MavenDomShortArtifactCoordinates coordinates) {
if (StringUtil.isEmpty(id.getGroupId())) {
Set<String> result = new THashSet<>();
for (String each : getGroupIdVariants(manager, coordinates)) {
for (String each : MavenArtifactUtil.DEFAULT_GROUPS) {
id = new MavenId(each, id.getArtifactId(), id.getVersion());
result.addAll(super.getVariants(id, manager, coordinates));
result.addAll(super.getVariants(id, searchService, coordinates));
}
return result;
}
return super.getVariants(id, manager, coordinates);
}
private String[] getGroupIdVariants(MavenProjectIndicesManager manager, MavenDomShortArtifactCoordinates coordinates) {
if (DomUtil.hasXml(coordinates.getGroupId())) {
Set<String> strings = manager.getGroupIds();
return ArrayUtil.toStringArray(strings);
}
return MavenArtifactUtil.DEFAULT_GROUPS;
return super.getVariants(id, searchService, coordinates);
}
@Override
@@ -22,10 +22,12 @@ import org.jetbrains.idea.maven.dom.model.MavenDomDependency;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenArtifact;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.project.MavenProject;
import java.util.Collection;
import java.util.Set;
import java.util.stream.Collectors;
public class MavenArtifactCoordinatesGroupIdConverter extends MavenArtifactCoordinatesConverter implements MavenSmartConverter<String> {
@Override
@@ -34,7 +36,7 @@ public class MavenArtifactCoordinatesGroupIdConverter extends MavenArtifactCoord
if (manager.hasGroupId(id.getGroupId())) return true;
// Check if artifact was found on importing.
// Check if artifact was found on importing.
MavenProject mavenProject = findMavenProject(context);
if (mavenProject != null) {
for (MavenArtifact artifact : mavenProject.findDependencies(id.getGroupId(), id.getArtifactId())) {
@@ -48,8 +50,8 @@ public class MavenArtifactCoordinatesGroupIdConverter extends MavenArtifactCoord
}
@Override
protected Set<String> doGetVariants(MavenId id, MavenProjectIndicesManager manager) {
return manager.getGroupIds();
protected Set<String> doGetVariants(MavenId id, DependencySearchService searchService) {
return searchService.findGroupCandidates(id).stream().map(s -> s.getGroupId()).collect(Collectors.toSet());
}
@Nullable
@@ -88,7 +90,7 @@ public class MavenArtifactCoordinatesGroupIdConverter extends MavenArtifactCoord
context.commitDocument();
PsiFile contextFile = context.getFile();
if(!(contextFile instanceof XmlFile)) return;
if (!(contextFile instanceof XmlFile)) return;
XmlFile xmlFile = (XmlFile)contextFile;
@@ -109,5 +111,4 @@ public class MavenArtifactCoordinatesGroupIdConverter extends MavenArtifactCoord
MavenDependencyCompletionUtil.addTypeAndClassifierAndVersion(context, dependency, item.getLookupString(), artifactId);
}
}
}
@@ -36,8 +36,8 @@ public class MavenArtifactCoordinatesHelper {
if (coords instanceof MavenDomArtifactCoordinates) {
version = ((MavenDomArtifactCoordinates)coords).getVersion().getStringValue();
}
return new MavenId(coords.getGroupId().getStringValue(),
coords.getArtifactId().getStringValue(),
version);
return new MavenId(MavenDependencyCompletionUtil.removeDummy(coords.getGroupId().getStringValue()),
MavenDependencyCompletionUtil.removeDummy(coords.getArtifactId().getStringValue()),
MavenDependencyCompletionUtil.removeDummy(version));
}
}
@@ -19,6 +19,7 @@ import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.xml.ConvertContext;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import java.util.Collections;
import java.util.Set;
@@ -40,7 +41,7 @@ public class MavenArtifactCoordinatesVersionConverter extends MavenArtifactCoord
}
@Override
protected Set<String> doGetVariants(MavenId id, MavenProjectIndicesManager manager) {
protected Set<String> doGetVariants(MavenId id, DependencySearchService searchService) {
// Do nothing. Completion variants are generated by MavenVersionCompletionContributor.
return Collections.emptySet();
}
@@ -18,19 +18,28 @@ package org.jetbrains.idea.maven.dom.converters;
import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Ref;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.xml.DomElement;
import com.intellij.util.xml.DomUtil;
import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.MavenDomProjectProcessorUtils;
import org.jetbrains.idea.maven.dom.model.*;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.Set;
import javax.swing.*;
import java.util.List;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER_TRIMMED;
/**
* @author Sergey Evdokimov
@@ -89,11 +98,11 @@ public class MavenDependencyCompletionUtil {
}
}
MavenProjectIndicesManager manager = MavenProjectIndicesManager.getInstance(project);
DependencySearchService service = MavenProjectIndicesManager.getInstance(project).getSearchService();
Set<String> versions = manager.getVersions(groupId, artifactId);
List<MavenDependencyCompletionItem> versions = service.findAllVersions(new MavenDependencyCompletionItem(groupId, artifactId, null));
if (versions.size() == 1) {
dependency.getVersion().setStringValue(ContainerUtil.getFirstItem(versions));
dependency.getVersion().setStringValue(ContainerUtil.getFirstItem(versions).getVersion());
return;
}
@@ -113,4 +122,57 @@ public class MavenDependencyCompletionUtil {
() -> new CodeCompletionHandlerBase(completionType).invokeCompletion(context.getProject(), context.getEditor()));
}
public static LookupElementBuilder lookupElement(MavenDependencyCompletionItem item, String lookup) {
return LookupElementBuilder.create(item, lookup)
.withIcon(getIcon(item.getType()));
}
public static LookupElementBuilder lookupElement(MavenDependencyCompletionItem item) {
return lookupElement(item, getLookupString(item));
}
@Nullable
public static Icon getIcon(@Nullable MavenDependencyCompletionItem.Type type) {
if (type == null) {
return null;
}
switch (type) {
case REMOTE:
return AllIcons.Nodes.PpWeb;
case LOCAL:
return AllIcons.Nodes.PpLibFolder;
case CACHED_ERROR:
return AllIcons.Nodes.PpInvalid;
}
return null;
}
public static String getLookupString(MavenDependencyCompletionItem description) {
StringBuilder builder = new StringBuilder(description.getGroupId());
if (description.getArtifactId() == null) {
builder.append(":...");
}
else {
builder.append(":").append(description.getArtifactId());
if (description.getPackaging() != null) {
builder.append(":").append(description.getPackaging());
}
if (description.getVersion() != null) {
builder.append(":").append(description.getVersion());
}
else {
builder.append(":...");
}
}
return builder.toString();
}
public static @NotNull String removeDummy(@Nullable String str) {
if(str ==null){
return "";
}
return StringUtil.trim(str.replace(DUMMY_IDENTIFIER, "").replace(DUMMY_IDENTIFIER_TRIMMED, ""));
}
}
@@ -15,6 +15,7 @@
*/
package org.jetbrains.idea.maven.dom.model;
import com.intellij.ide.presentation.Presentation;
import com.intellij.spellchecker.xml.NoSpellchecking;
import com.intellij.util.xml.Convert;
import com.intellij.util.xml.DomElement;
@@ -22,7 +23,10 @@ import com.intellij.util.xml.GenericDomValue;
import com.intellij.util.xml.Required;
import org.jetbrains.idea.maven.dom.converters.MavenArtifactCoordinatesArtifactIdConverter;
import org.jetbrains.idea.maven.dom.converters.MavenArtifactCoordinatesGroupIdConverter;
import org.jetbrains.idea.maven.dom.model.presentation.MavenArtifactCoordinatesPresentationProvider;
@Presentation(typeName = "Dependency", icon = "AllIcons.Nodes.PpLib", provider = MavenArtifactCoordinatesPresentationProvider.class)
public interface MavenDomShortArtifactCoordinates extends DomElement {
@Required
@NoSpellchecking
@@ -0,0 +1,100 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.dom.model.completion;
import com.intellij.codeInsight.completion.CompletionContributor;
import com.intellij.codeInsight.completion.CompletionParameters;
import com.intellij.codeInsight.completion.CompletionResultSet;
import com.intellij.psi.PsiElement;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlText;
import com.intellij.psi.xml.XmlTokenType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.dom.converters.MavenDependencyCompletionUtil;
import org.jetbrains.idea.maven.dom.model.completion.insert.MavenDependencyInsertHandler;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.utils.MavenLog;
import java.util.List;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER_TRIMMED;
public class MavenArtifactCompletionContributor extends CompletionContributor {
@Override
public void fillCompletionVariants(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet result) {
if (System.currentTimeMillis() > 1) return;
try {
PsiElement xmlText = parameters.getPosition().getParent();
if (!(xmlText instanceof XmlText)) return;
PsiElement tag = xmlText.getParent();
if (!(tag instanceof XmlTag)) return;
XmlTag parentTag = (XmlTag)tag;
XmlText currentText = (XmlText)xmlText;
if (!PsiImplUtil.isLeafElementOfType(xmlText.getPrevSibling(), XmlTokenType.XML_TAG_END)
|| !PsiImplUtil.isLeafElementOfType(xmlText.getNextSibling(), XmlTokenType.XML_END_TAG_START)) {
return;
}
if ("dependency".equals(parentTag.getName())) {
fillAllVariants(parameters, result, currentText, parentTag, MavenProjectIndicesManager.getInstance(tag.getProject()));
}
}
catch (Exception e) {
MavenLog.LOG.error(e);
}
}
private static String getCoordValue(XmlTag dependencyTag, final String tagName) {
String result = null;
for (XmlTag sub : dependencyTag.getSubTags()) {
if (tagName.equals(sub.getName())) {
XmlText type = PsiTreeUtil.getChildOfType(sub, XmlText.class);
if (type == null) {
break;
}
else {
result = type.getValue();
}
}
}
return result;
}
private void addToResultSet(CompletionResultSet result, XmlTag dependencyTag, List<MavenDependencyCompletionItem> candidates) {
for (MavenDependencyCompletionItem description : candidates) {
if (description.getGroupId() == null) {
continue;
}
result.addElement(MavenDependencyCompletionUtil.lookupElement(description)
.withInsertHandler(MavenDependencyInsertHandler.INSTANCE));
}
}
private void fillAllVariants(CompletionParameters parameters,
CompletionResultSet result,
XmlText xmlText,
XmlTag dependencyTag, MavenProjectIndicesManager instance) {
List<MavenDependencyCompletionItem> candidates = instance.getSearchService().findByTemplate(
getText(xmlText));
addToResultSet(result, dependencyTag, candidates);
}
@NotNull
private static String getText(XmlText text) {
return text.getValue().replace(DUMMY_IDENTIFIER, "").replace(DUMMY_IDENTIFIER_TRIMMED, "");
}
}
@@ -4,8 +4,6 @@ package org.jetbrains.idea.maven.dom.model.completion;
import com.intellij.codeInsight.actions.ReformatCodeProcessor;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiElement;
@@ -23,6 +21,14 @@ import org.jetbrains.idea.maven.dom.converters.MavenDependencyCompletionUtil;
import org.jetbrains.idea.maven.dom.model.MavenDomDependency;
import org.jetbrains.idea.maven.dom.model.MavenDomProjectModel;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.onlinecompletion.MavenScopeTable;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.List;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER;
import static com.intellij.codeInsight.completion.CompletionUtil.DUMMY_IDENTIFIER_TRIMMED;
import static com.intellij.patterns.StandardPatterns.string;
/**
* @author Sergey Evdokimov
@@ -43,7 +49,7 @@ public class MavenDependenciesCompletionProvider extends CompletionContributor {
if (!"dependency".equals(dependencyTag.getName())) return;
if (!PsiImplUtil.isLeafElementOfType(xmlText.getPrevSibling(), XmlTokenType.XML_TAG_END)
|| !PsiImplUtil.isLeafElementOfType(xmlText.getNextSibling(), XmlTokenType.XML_END_TAG_START)) {
|| !PsiImplUtil.isLeafElementOfType(xmlText.getNextSibling(), XmlTokenType.XML_END_TAG_START)) {
return;
}
@@ -54,16 +60,14 @@ public class MavenDependenciesCompletionProvider extends CompletionContributor {
return;
}
MavenProjectIndicesManager indicesManager = MavenProjectIndicesManager.getInstance(project);
for (String groupId : indicesManager.getGroupIds()) {
for (String artifactId : indicesManager.getArtifactIds(groupId)) {
LookupElement builder = LookupElementBuilder.create(groupId + ':' + artifactId)
.withIcon(AllIcons.Nodes.PpLib).withInsertHandler(MavenDependencyInsertHandler.INSTANCE);
List<MavenDependencyCompletionItem> candidates = MavenProjectIndicesManager.getInstance(project).getSearchService().findByTemplate(
StringUtil.trim(xmlText.getText().replace(DUMMY_IDENTIFIER, "").replace(DUMMY_IDENTIFIER_TRIMMED, "")));
result.addElement(builder);
}
for (MavenDependencyCompletionItem candidate : candidates) {
result.addElement(MavenDependencyCompletionUtil.lookupElement(candidate).withInsertHandler(MavenDependencyInsertHandler.INSTANCE));
}
result.restartCompletionOnPrefixChange(string().containsChars(":-."));
}
private static class MavenDependencyInsertHandler implements InsertHandler<LookupElement> {
@@ -72,38 +76,50 @@ public class MavenDependenciesCompletionProvider extends CompletionContributor {
@Override
public void handleInsert(@NotNull final InsertionContext context, @NotNull LookupElement item) {
String s = item.getLookupString();
int idx = s.indexOf(':');
Object obj = item.getObject();
if (!(obj instanceof MavenDependencyCompletionItem)) {
return;
}
String groupId = s.substring(0, idx);
String artifactId = s.substring(idx + 1);
MavenDependencyCompletionItem dependencyToSet = (MavenDependencyCompletionItem)obj;
int startOffset = context.getStartOffset();
PsiFile psiFile = context.getFile();
DomFileElement<MavenDomProjectModel> domModel = DomManager.getDomManager(context.getProject()).getFileElement((XmlFile)psiFile, MavenDomProjectModel.class);
DomFileElement<MavenDomProjectModel> domModel =
DomManager.getDomManager(context.getProject()).getFileElement((XmlFile)psiFile, MavenDomProjectModel.class);
if (domModel == null) return;
boolean shouldInvokeCompletion = false;
MavenDomDependency managedDependency = MavenDependencyCompletionUtil.findManagedDependency(domModel.getRootElement(),
context.getProject(), groupId, artifactId);
MavenDomDependency managedDependency = findManagedDomDependency(context, dependencyToSet, domModel);
if (managedDependency == null) {
String value = "<groupId>" + groupId + "</groupId>\n" +
"<artifactId>" + artifactId + "</artifactId>\n" +
"<version></version>";
String classifier =
dependencyToSet.getClassifier() == null ? "" : "<classifier>" + dependencyToSet.getClassifier() + "</classifier>\n";
String packaging =
dependencyToSet.getPackaging() == null || dependencyToSet.getPackaging().equals("jar")
? ""
: "<packaging>" + dependencyToSet.getPackaging() + "</packaging>\n";
String usualScope = MavenScopeTable.getUsualScope(dependencyToSet);
String scope = usualScope == null ? "" : "<scope>" + usualScope + "</scope>\n";
String version = dependencyToSet.getVersion() == null ? "" : dependencyToSet.getVersion();
String value = "<groupId>" + dependencyToSet.getGroupId() + "</groupId>\n" +
"<artifactId>" + dependencyToSet.getArtifactId() + "</artifactId>\n" +
classifier + packaging + scope +
"<version>" + version + "</version>";
context.getDocument().replaceString(startOffset, context.getSelectionEndOffset(), value);
context.getEditor().getCaretModel().moveToOffset(startOffset + value.length() - 10);
shouldInvokeCompletion = true;
if (dependencyToSet.getVersion() == null) {
context.getEditor().getCaretModel().moveToOffset(startOffset + value.length() - "</version>".length());
shouldInvokeCompletion = true;
}
}
else {
StringBuilder sb = new StringBuilder();
sb.append("<groupId>").append(groupId).append("</groupId>\n")
.append("<artifactId>").append(artifactId).append("</artifactId>\n");
sb.append("<groupId>").append(dependencyToSet.getGroupId()).append("</groupId>\n")
.append("<artifactId>").append(dependencyToSet.getArtifactId()).append("</artifactId>\n");
String type = managedDependency.getType().getRawText();
if (type != null && !type.equals("jar")) {
@@ -133,5 +149,17 @@ public class MavenDependenciesCompletionProvider extends CompletionContributor {
MavenDependencyCompletionUtil.invokeCompletion(context, CompletionType.BASIC);
}
}
private MavenDomDependency findManagedDomDependency(@NotNull InsertionContext context,
MavenDependencyCompletionItem dependencyToSet,
DomFileElement<MavenDomProjectModel> domModel) {
if (dependencyToSet.getGroupId() == null || dependencyToSet.getArtifactId() == null) {
return null;
}
return MavenDependencyCompletionUtil.findManagedDependency(domModel.getRootElement(),
context.getProject(),
dependencyToSet.getGroupId(),
dependencyToSet.getArtifactId());
}
}
}
@@ -15,7 +15,6 @@
*/
package org.jetbrains.idea.maven.dom.model.completion;
import com.google.common.collect.Sets;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.completion.impl.NegatingComparable;
import com.intellij.codeInsight.lookup.LookupElement;
@@ -33,13 +32,14 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.MavenVersionComparable;
import org.jetbrains.idea.maven.dom.converters.MavenArtifactCoordinatesVersionConverter;
import org.jetbrains.idea.maven.dom.converters.MavenDependencyCompletionUtil;
import org.jetbrains.idea.maven.dom.model.MavenDomArtifactCoordinates;
import org.jetbrains.idea.maven.dom.model.MavenDomPlugin;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
import org.jetbrains.idea.maven.utils.MavenArtifactUtil;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.server.MavenServerManager;
import org.jetbrains.idea.maven.utils.library.RepositoryLibraryDescription;
import java.util.Set;
import java.util.List;
/**
* @author Sergey Evdokimov
@@ -61,6 +61,10 @@ public class MavenVersionCompletionContributor extends CompletionContributor {
XmlTag tag = (XmlTag)tagElement;
if (!"version".equals(tag.getName())) {
return;
}
Project project = element.getProject();
DomElement domElement = DomManager.getDomManager(project).getDomElement(tag);
@@ -78,6 +82,7 @@ public class MavenVersionCompletionContributor extends CompletionContributor {
if (StringUtil.isEmptyOrSpaces(artifactId)) return;
CompletionResultSet newResultSet = result.withRelevanceSorter(CompletionService.getCompletionService().emptySorter().weigh(
new LookupElementWeigher("mavenVersionWeigher") {
@Nullable
@@ -87,28 +92,23 @@ public class MavenVersionCompletionContributor extends CompletionContributor {
}
}));
MavenProjectIndicesManager indicesManager = MavenProjectIndicesManager.getInstance(project);
List<MavenDependencyCompletionItem> completionItems = searchVersions(groupId, artifactId, coordinates, project);
Set<String> versions;
if (StringUtil.isEmptyOrSpaces(groupId)) {
if (!(coordinates instanceof MavenDomPlugin)) return;
versions = indicesManager.getVersions(MavenArtifactUtil.DEFAULT_GROUPS[0], artifactId);
for (int i = 0; i < MavenArtifactUtil.DEFAULT_GROUPS.length; i++) {
versions = Sets.union(versions, indicesManager.getVersions(MavenArtifactUtil.DEFAULT_GROUPS[i], artifactId));
}
for (MavenDependencyCompletionItem item : completionItems) {
newResultSet.addElement(MavenDependencyCompletionUtil.lookupElement(item, item.getVersion()));
}
else {
versions = indicesManager.getVersions(groupId, artifactId);
if (MavenServerManager.getInstance().isUseMaven2()) {
newResultSet.addElement(LookupElementBuilder.create(RepositoryLibraryDescription.ReleaseVersionId).withStrikeoutness(true));
newResultSet.addElement(LookupElementBuilder.create(RepositoryLibraryDescription.LatestVersionId).withStrikeoutness(true));
}
for (String version : versions) {
newResultSet.addElement(LookupElementBuilder.create(version));
}
newResultSet.addElement(LookupElementBuilder.create(RepositoryLibraryDescription.ReleaseVersionId));
newResultSet.addElement(LookupElementBuilder.create(RepositoryLibraryDescription.LatestVersionId));
}
}
private List<MavenDependencyCompletionItem> searchVersions(String groupId,
String artifactId,
MavenDomArtifactCoordinates coordinates,
Project project) {
return MavenProjectIndicesManager.getInstance(project).getSearchService()
.findAllVersions(new MavenDependencyCompletionItem(groupId, artifactId, null, null));
}
}
@@ -0,0 +1,126 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.dom.model.completion.insert;
import com.intellij.codeInsight.actions.ReformatCodeProcessor;
import com.intellij.codeInsight.completion.CompletionType;
import com.intellij.codeInsight.completion.InsertHandler;
import com.intellij.codeInsight.completion.InsertionContext;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.xml.XmlTagImpl;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.dom.converters.MavenDependencyCompletionUtil;
import org.jetbrains.idea.maven.onlinecompletion.MavenScopeTable;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.utils.MavenLog;
public class MavenDependencyInsertHandler implements InsertHandler<LookupElement> {
public static final InsertHandler<LookupElement> INSTANCE = new MavenDependencyInsertHandler();
@Override
public void handleInsert(@NotNull final InsertionContext context, @NotNull LookupElement item) {
try {
doHandleInsert(context, item);
}
catch (Throwable e) {
MavenLog.LOG.error(e);
}
}
private void doHandleInsert(@NotNull final InsertionContext context, @NotNull LookupElement item) {
MavenDependencyCompletionItem mavenId = extract(item);
int startOffset = context.getStartOffset();
PsiFile psiFile = context.getFile();
XmlTagImpl dependencyTag = getDependencyTag(startOffset, psiFile);
if (dependencyTag == null) {
return;
}
boolean shouldInvokeCompletion = setDependency(context, mavenId, dependencyTag);
context.commitDocument();
PsiElement e = getDependencyTag(startOffset, psiFile);
if (e != null) {
new ReformatCodeProcessor(psiFile.getProject(), psiFile, e.getTextRange(), false).run();
}
if (shouldInvokeCompletion) {
MavenDependencyCompletionUtil.invokeCompletion(context, CompletionType.BASIC);
}
}
@Nullable
private XmlTagImpl getDependencyTag(int startOffset, PsiFile psiFile) {
PsiElement e = psiFile.findElementAt(startOffset);
while (e != null && (!(e instanceof XmlTagImpl) || !"dependency".equals(((XmlTagImpl)e).getName()))) {
e = e.getParent();
}
return (XmlTagImpl)e;
}
private boolean setDependency(@NotNull InsertionContext context,
@NotNull MavenDependencyCompletionItem item, XmlTagImpl dependencyTag) {
int startOffset = dependencyTag.getStartOffset() + "<dependency>".length();
int endOffset = dependencyTag.getTextRange().getEndOffset();
while ("\n".equals(context.getDocument().getText(new TextRange(endOffset - 1, endOffset)))) {
endOffset--;
}
endOffset -= "</dependency>".length();
if (item.getGroupId() == null) {
return false;
}
else if (item.getArtifactId() == null) {
String value = "\n<groupId>" + item.getGroupId() + "</groupId>\n" +
"<artifactId></artifactId>";
context.getDocument().replaceString(startOffset, endOffset, value);
context.getEditor().getCaretModel().moveToOffset(startOffset + value.length() - "</artifactId>".length());
return true;
}
else if (item.getVersion() == null) {
String value = "\n<groupId>" + item.getGroupId() + "</groupId>\n" +
"<artifactId>" + item.getArtifactId() + "</artifactId>\n" +
"<version></version>\n";
context.getDocument().replaceString(startOffset, endOffset, value);
context.getEditor().getCaretModel().moveToOffset(startOffset + value.length() - "</version>".length());
return true;
}
else {
String classifier = item.getClassifier() == null ? "" : "<classifier>" + item.getClassifier() + "</classifier>\n";
String packaging =
item.getPackaging() == null || item.getPackaging().equals("jar") ? "" : "<packaging>" + item.getPackaging() + "</packaging>\n";
String usualScope = MavenScopeTable.getUsualScope(item);
String scope = usualScope == null ? "" : "<scope>" + usualScope + "</scope>\n";
String value = "\n<groupId>" + item.getGroupId() + "</groupId>\n" +
"<artifactId>" + item.getArtifactId() + "</artifactId>\n" +
classifier + packaging + scope +
"<version>" + item.getVersion() + "</version>\n";
context.getDocument().replaceString(startOffset, endOffset, value);
return false;
}
}
private static MavenDependencyCompletionItem extract(LookupElement item) {
Object object = item.getObject();
if (object instanceof MavenDependencyCompletionItem) {
return (MavenDependencyCompletionItem)object;
}
else {
return new MavenDependencyCompletionItem(item.getLookupString(), null);
}
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.application.ApplicationManager;
@@ -1,4 +1,4 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.icons.AllIcons;
@@ -14,8 +14,9 @@ import com.intellij.util.Alarm;
import com.intellij.util.ui.AbstractLayoutManager;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.dom.converters.MavenDependencyCompletionUtil;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.utils.MavenLog;
import javax.swing.*;
@@ -180,7 +181,7 @@ public class MavenArtifactSearchPanel extends JPanel {
for (MavenArtifactSearchResult searchResult : result) {
if (searchResult.versions.isEmpty()) continue;
MavenArtifactInfo artifactInfo = searchResult.versions.get(0);
MavenDependencyCompletionItem artifactInfo = searchResult.getSearchResults().get(0);
final String managedVersion = myManagedDependenciesMap.get(Pair.create(artifactInfo.getGroupId(), artifactInfo.getArtifactId()));
if (managedVersion != null) {
Collections.sort(searchResult.versions, (o1, o2) -> {
@@ -219,12 +220,12 @@ public class MavenArtifactSearchPanel extends JPanel {
for (TreePath each : myResultList.getSelectionPaths()) {
Object sel = each.getLastPathComponent();
MavenArtifactInfo info;
if (sel instanceof MavenArtifactInfo) {
info = (MavenArtifactInfo)sel;
MavenDependencyCompletionItem info;
if (sel instanceof MavenDependencyCompletionItem) {
info = (MavenDependencyCompletionItem)sel;
}
else {
info = ((MavenArtifactSearchResult)sel).versions.get(0);
info = ((MavenArtifactSearchResult)sel).getSearchResults().get(0);
}
result.add(new MavenId(info.getGroupId(), info.getArtifactId(), info.getVersion()));
}
@@ -357,17 +358,20 @@ public class MavenArtifactSearchPanel extends JPanel {
else if (value instanceof MavenArtifactSearchResult) {
formatSearchResult(tree, (MavenArtifactSearchResult)value, selected);
}
else if (value instanceof MavenArtifactInfo) {
MavenArtifactInfo info = (MavenArtifactInfo)value;
else if (value instanceof MavenDependencyCompletionItem) {
MavenDependencyCompletionItem info = (MavenDependencyCompletionItem)value;
String version = info.getVersion();
Icon icon = MavenDependencyCompletionUtil.getIcon(info.getType());
String managedVersion = myManagedDependenciesMap.get(Pair.create(info.getGroupId(), info.getArtifactId()));
if (managedVersion != null && managedVersion.equals(version)) {
myLeftComponent.setIcon(icon);
myLeftComponent.append(version, SimpleTextAttributes.REGULAR_BOLD_ATTRIBUTES);
myLeftComponent.append(" (from <dependencyManagement>)", SimpleTextAttributes.GRAYED_ATTRIBUTES);
}
else {
myLeftComponent.setIcon(icon);
myLeftComponent.append(version, SimpleTextAttributes.REGULAR_ATTRIBUTES);
}
}
@@ -376,12 +380,12 @@ public class MavenArtifactSearchPanel extends JPanel {
}
protected void formatSearchResult(JTree tree, MavenArtifactSearchResult searchResult, boolean selected) {
MavenArtifactInfo info = searchResult.versions.get(0);
MavenDependencyCompletionItem info = searchResult.getSearchResults().get(0);
myLeftComponent.setIcon(AllIcons.Nodes.PpLib);
appendArtifactInfo(myLeftComponent, info, selected);
}
protected void appendArtifactInfo(SimpleColoredComponent component, MavenArtifactInfo info, boolean selected) {
protected void appendArtifactInfo(SimpleColoredComponent component, MavenDependencyCompletionItem info, boolean selected) {
component.append(info.getGroupId() + ":", getGrayAttributes(selected));
component.append(info.getArtifactId(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
component.append(":" + info.getVersion(), getGrayAttributes(selected));
@@ -401,11 +405,11 @@ public class MavenArtifactSearchPanel extends JPanel {
@Override
protected void formatSearchResult(JTree tree, MavenArtifactSearchResult searchResult, boolean selected) {
MavenClassSearchResult classResult = (MavenClassSearchResult)searchResult;
MavenArtifactInfo info = searchResult.versions.get(0);
MavenDependencyCompletionItem info = searchResult.getSearchResults().get(0);
myLeftComponent.setIcon(AllIcons.Nodes.Class);
myLeftComponent.append(classResult.className, SimpleTextAttributes.REGULAR_ATTRIBUTES);
myLeftComponent.append(" (" + classResult.packageName + ")", getGrayAttributes(selected));
myLeftComponent.append(classResult.getClassName(), SimpleTextAttributes.REGULAR_ATTRIBUTES);
myLeftComponent.append(" (" + classResult.getPackageName() + ")", getGrayAttributes(selected));
appendArtifactInfo(myRightComponent, info, selected);
}
@@ -1,26 +1,44 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MavenArtifactSearchResult {
public List<MavenArtifactInfo> versions = new ArrayList<>();
@Deprecated
/* @deprecated use getSearchResults instead */
public List<MavenArtifactInfo> versions;
private List<MavenDependencyCompletionItem> myResults;
@Deprecated
public MavenArtifactSearchResult() {
this(new ArrayList<>());
}
public MavenArtifactSearchResult(@NotNull List<MavenDependencyCompletionItem> results) {
setVersions(results);
this.myResults = results;
}
public void setResults(List<MavenDependencyCompletionItem> results) {
setVersions(results);
myResults = results;
}
private void setVersions(@NotNull List<MavenDependencyCompletionItem> results) {
versions = ContainerUtil.map(results, d -> new MavenArtifactInfo(d, d.getPackaging(), d.getClassifier()));
}
public List<MavenDependencyCompletionItem> getSearchResults(){
return Collections.unmodifiableList(myResults);
}
}
@@ -1,77 +1,51 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import com.intellij.util.containers.hash.HashMap;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import java.util.*;
import static com.intellij.openapi.util.text.StringUtil.*;
import static org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters.Flags.ALL_VERSIONS;
import static org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters.Flags.FULL_RESOLVE;
public class MavenArtifactSearcher extends MavenSearcher<MavenArtifactSearchResult> {
private static final Pattern VERSION_PATTERN = Pattern.compile("[.\\d]+");
@Override
protected List<MavenArtifactSearchResult> searchImpl(Project project, String pattern, int maxResult) {
List<String> parts = new ArrayList<>();
for (String each : tokenize(pattern, " :")) {
parts.add(trimStart(trimEnd(each, "*"), "*"));
if (StringUtil.isEmpty(pattern)) {
return Collections.emptyList();
}
DependencySearchService service = MavenProjectIndicesManager.getInstance(project).getSearchService();
List<MavenDependencyCompletionItem> searchResults =
service.findByTemplate(pattern, new SearchParameters(1000, 5000, EnumSet.of(FULL_RESOLVE, ALL_VERSIONS)));
return processResults(searchResults, pattern);
}
List<MavenArtifactSearchResult> searchResults = ContainerUtil.newSmartList();
MavenProjectIndicesManager m = MavenProjectIndicesManager.getInstance(project);
int count = 0;
List<MavenArtifactInfo> versions = new ArrayList<>();
for (String groupId : m.getGroupIds()) {
if (count >= maxResult) break;
if (parts.size() < 1 || contains(groupId, parts.get(0))) {
for (String artifactId : m.getArtifactIds(groupId)) {
if (parts.size() < 2 || contains(artifactId, parts.get(1))) {
for (String version : m.getVersions(groupId, artifactId)) {
if (parts.size() < 3 || contains(version, parts.get(2))) {
versions.add(new MavenArtifactInfo(groupId, artifactId, version, "jar", null));
if (++count >= maxResult) break;
}
}
}
else if (parts.size() == 2 && VERSION_PATTERN.matcher(parts.get(1)).matches()) {
for (String version : m.getVersions(groupId, artifactId)) {
if (contains(version, parts.get(1))) {
versions.add(new MavenArtifactInfo(groupId, artifactId, version, "jar", null));
if (++count >= maxResult) break;
}
}
}
if (!versions.isEmpty()) {
MavenArtifactSearchResult searchResult = new MavenArtifactSearchResult();
searchResult.versions.addAll(versions);
searchResults.add(searchResult);
versions.clear();
}
if (count >= maxResult) break;
}
private static List<MavenArtifactSearchResult> processResults(List<MavenDependencyCompletionItem> searchResults, String pattern) {
Map<String, List<MavenDependencyCompletionItem>> results = new HashMap<>();
for (MavenDependencyCompletionItem item : searchResults) {
if (item.getGroupId() == null || item.getArtifactId() == null || item.getVersion() == null) {
continue;
}
String key = item.getGroupId() + ":" + item.getArtifactId();
if(!key.contains(pattern)){
continue;
}
List<MavenDependencyCompletionItem> list = results.get(key);
if (list == null) {
list = new ArrayList<>();
results.put(key, list);
}
list.add(item);
}
return searchResults;
;
return ContainerUtil.map(results.values(), MavenArtifactSearchResult::new);
}
}
@@ -1,21 +1,30 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.List;
public class MavenClassSearchResult extends MavenArtifactSearchResult {
@Deprecated
/* @deprecated use getClassName */
public String className;
@Deprecated
/* @deprecated use getPackageName */
public String packageName;
public MavenClassSearchResult(@NotNull List<MavenDependencyCompletionItem> results, String className, String packageName) {
super(results);
this.className = className;
this.packageName = packageName;
}
public String getClassName() {
return className;
}
public String getPackageName() {
return packageName;
}
}
@@ -1,53 +1,34 @@
/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.text.StringUtil;
import gnu.trove.THashMap;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.MatchAllDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.WildcardQuery;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import org.jetbrains.idea.maven.server.MavenServerIndexer;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import static org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters.Flags.ALL_VERSIONS;
import static org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters.Flags.FULL_RESOLVE;
public class MavenClassSearcher extends MavenSearcher<MavenClassSearchResult> {
public static final String TERM = MavenServerIndexer.SEARCH_TERM_CLASS_NAMES;
@Override
protected List<MavenClassSearchResult> searchImpl(Project project, String pattern, int maxResult) {
Pair<String, Query> patternAndQuery = preparePatternAndQuery(pattern);
MavenProjectIndicesManager m = MavenProjectIndicesManager.getInstance(project);
Set<MavenArtifactInfo> infos = m.search(patternAndQuery.second, maxResult);
return new ArrayList<>(processResults(infos, patternAndQuery.first, maxResult));
DependencySearchService service = MavenProjectIndicesManager.getInstance(project).getSearchService();
List<MavenDependencyCompletionItemWithClass> items = service.findClasses(pattern, new SearchParameters(1000, 5000, EnumSet
.of(FULL_RESOLVE, ALL_VERSIONS)));
return processResults(items, maxResult);
}
protected Pair<String, Query> preparePatternAndQuery(String pattern) {
protected String preparePattern(String pattern) {
pattern = pattern.toLowerCase();
if (pattern.trim().length() == 0) {
return new Pair<>(pattern, new MatchAllDocsQuery());
return pattern;
}
List<String> parts = StringUtil.split(pattern, ".");
@@ -64,81 +45,52 @@ public class MavenClassSearcher extends MavenSearcher<MavenClassSearchResult> {
newPattern.append(className.trim());
if (!exactSearch) newPattern.append("*");
pattern = newPattern.toString();
String queryPattern = "*/" + pattern.replaceAll("\\.", "/");
return new Pair<>(pattern, new WildcardQuery(new Term(TERM, queryPattern)));
return newPattern.toString();
}
protected Collection<MavenClassSearchResult> processResults(Set<MavenArtifactInfo> infos, String pattern, int maxResult) {
if (pattern.length() == 0 || pattern.equals("*")) {
pattern = "^/(.*)$";
}
else {
pattern = pattern.replace(".", "/");
protected List<MavenClassSearchResult> processResults(List<MavenDependencyCompletionItemWithClass> searchResults,
int maxResult) {
int lastDot = pattern.lastIndexOf("/");
String packagePattern = lastDot == -1 ? "" : (pattern.substring(0, lastDot) + "/");
String classNamePattern = lastDot == -1 ? pattern : pattern.substring(lastDot + 1);
Map<String, List<MavenDependencyCompletionItem>> classes = new HashMap<>();
packagePattern = packagePattern.replaceAll("\\*", ".*?");
classNamePattern = classNamePattern.replaceAll("\\*", "[^/]*?");
pattern = packagePattern + classNamePattern;
pattern = ".*?/" + pattern;
pattern = "^(" + pattern + ")$";
}
Pattern p;
try {
p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
}
catch (PatternSyntaxException e) {
return Collections.emptyList();
}
Map<String, MavenClassSearchResult> result = new THashMap<>();
for (MavenArtifactInfo each : infos) {
if (each.getClassNames() == null) continue;
Matcher matcher = p.matcher(each.getClassNames());
while (matcher.find()) {
String classFQName = matcher.group(1);
classFQName = classFQName.replace("/", ".");
classFQName = StringUtil.trimStart(classFQName, ".");
String key = makeKey(classFQName, each);
MavenClassSearchResult classResult = result.get(key);
if (classResult == null) {
classResult = new MavenClassSearchResult();
int pos = classFQName.lastIndexOf(".");
if (pos == -1) {
classResult.packageName = "default package";
classResult.className = classFQName;
}
else {
classResult.packageName = classFQName.substring(0, pos);
classResult.className = classFQName.substring(pos + 1);
}
result.put(key, classResult);
for (MavenDependencyCompletionItemWithClass item : searchResults) {
for (String className : item.getNames()) {
List<MavenDependencyCompletionItem> list = classes.get(className);
if (list == null) {
list = new ArrayList<>();
classes.put(className, list);
}
classResult.versions.add(each);
if (result.size() > maxResult) break;
list.add(item);
}
}
return result.values();
List<MavenClassSearchResult> results = new ArrayList<>();
for (Map.Entry<String, List<MavenDependencyCompletionItem>> entry : classes.entrySet()) {
String className;
String packageName;
int pos = entry.getKey().lastIndexOf(".");
if (pos == -1) {
packageName = "default package";
className = entry.getKey();
}
else {
packageName = entry.getKey().substring(0, pos);
className = entry.getKey().substring(pos + 1);
}
MavenClassSearchResult classResult = new MavenClassSearchResult(entry.getValue(), className, packageName);
results.add(classResult);
}
return results;
}
@Override
protected String makeSortKey(MavenClassSearchResult result) {
return makeKey(result.className, result.versions.get(0));
return makeKey(result.getClassName(), result.getSearchResults().get(0));
}
private String makeKey(String className, MavenArtifactInfo info) {
private String makeKey(String className, MavenDependencyCompletionItem info) {
return className + " " + super.makeKey(info);
}
}
@@ -1,18 +1,4 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import com.intellij.jarRepository.services.bintray.BintrayModel;
@@ -52,7 +38,8 @@ import static com.intellij.openapi.util.text.StringUtil.join;
import static com.intellij.openapi.util.text.StringUtil.split;
import static com.intellij.util.containers.ContainerUtil.notNullize;
public class MavenIndex {
@Deprecated
public class MavenIndex implements MavenSearchIndex {
private static final String CURRENT_VERSION = "5";
protected static final String INDEX_INFO_FILE = "index.properties";
@@ -72,10 +59,6 @@ public class MavenIndex {
private static final String VERSIONS_MAP_FILE = "versions-map.dat";
private static final String ARCHETYPES_MAP_FILE = "archetypes-map.dat";
public enum Kind {
LOCAL, REMOTE
}
private final MavenIndexerWrapper myNexusIndexer;
private final NotNexusIndexer myNotNexusIndexer;
private final File myDir;
@@ -170,6 +153,7 @@ public class MavenIndex {
return null;
}
@Override
public void registerId(String repositoryId) throws MavenIndexException {
if (myRegisteredRepositoryIds.add(repositoryId)) {
save();
@@ -252,6 +236,7 @@ public class MavenIndex {
}
}
@Override
public synchronized void close(boolean releaseIndexContext) {
try {
if (myData != null) myData.close(releaseIndexContext);
@@ -289,40 +274,49 @@ public class MavenIndex {
}
}
@Override
public String getRepositoryId() {
return myId.getValue();
}
@Override
public File getRepositoryFile() {
return myKind == Kind.LOCAL ? new File(myRepositoryPathOrUrl) : null;
}
@Override
public String getRepositoryUrl() {
return myKind == Kind.REMOTE ? myRepositoryPathOrUrl : null;
}
@Override
public String getRepositoryPathOrUrl() {
return myRepositoryPathOrUrl;
}
@Override
public Kind getKind() {
return myKind;
}
@Override
public boolean isFor(Kind kind, String pathOrUrl) {
if (myKind != kind) return false;
if (kind == Kind.LOCAL) return FileUtil.pathsEqual(myRepositoryPathOrUrl, normalizePathOrUrl(pathOrUrl));
return myRepositoryPathOrUrl.equalsIgnoreCase(normalizePathOrUrl(pathOrUrl));
}
@Override
public synchronized long getUpdateTimestamp() {
return myUpdateTimestamp == null ? -1 : myUpdateTimestamp;
}
@Override
public synchronized String getFailureMessage() {
return myFailureMessage;
}
@Override
public void updateOrRepair(boolean fullUpdate, MavenGeneralSettings settings, MavenProgressIndicator progress)
throws MavenProcessCanceledException {
try {
@@ -401,7 +395,7 @@ public class MavenIndex {
synchronized (this) {
IndexData oldData = myData;
if(oldData != null) {
if (oldData != null) {
oldData.close(true);
}
}
@@ -748,10 +742,6 @@ public class MavenIndex {
}
}
public interface IndexListener {
void indexIsBroken(@NotNull MavenIndex index);
}
private class MyIndexRepositoryIdsProvider implements CachedValueProvider<String> {
@Nullable
@Override
@@ -33,12 +33,12 @@ public class MavenIndices {
private final MavenIndexerWrapper myIndexer;
private final File myIndicesDir;
private final MavenIndex.IndexListener myListener;
private final MavenSearchIndex.IndexListener myListener;
private final List<MavenIndex> myIndices = new ArrayList<>();
private static final Object ourDirectoryLock = new Object();
public MavenIndices(MavenIndexerWrapper indexer, File indicesDir, MavenIndex.IndexListener listener) {
public MavenIndices(MavenIndexerWrapper indexer, File indicesDir, MavenSearchIndex.IndexListener listener) {
myIndexer = indexer;
myIndicesDir = indicesDir;
myListener = listener;
@@ -71,7 +71,7 @@ public class MavenIndices {
}
public synchronized void close() {
for (MavenIndex each : myIndices) {
for (MavenSearchIndex each : myIndices) {
each.close(false);
}
myIndices.clear();
@@ -81,7 +81,7 @@ public class MavenIndices {
return new ArrayList<>(myIndices);
}
public synchronized MavenIndex add(String repositoryId, String repositoryPathOrUrl, MavenIndex.Kind kind) throws MavenIndexException {
public synchronized MavenIndex add(String repositoryId, String repositoryPathOrUrl, MavenSearchIndex.Kind kind) throws MavenIndexException {
MavenIndex index = find(repositoryPathOrUrl, kind);
if (index != null) {
index.registerId(repositoryId);
@@ -95,7 +95,7 @@ public class MavenIndices {
}
@Nullable
public MavenIndex find(String repositoryPathOrUrl, MavenIndex.Kind kind) {
public MavenIndex find(String repositoryPathOrUrl, MavenSearchIndex.Kind kind) {
for (MavenIndex each : myIndices) {
if (each.isFor(kind, repositoryPathOrUrl)) return each;
}
@@ -123,7 +123,7 @@ public class MavenIndices {
}
}
public static void updateOrRepair(MavenIndex index, boolean fullUpdate, MavenGeneralSettings settings, MavenProgressIndicator progress)
public static void updateOrRepair(MavenSearchIndex index, boolean fullUpdate, MavenGeneralSettings settings, MavenProgressIndicator progress)
throws MavenProcessCanceledException {
index.updateOrRepair(fullUpdate, settings, progress);
}
@@ -56,8 +56,8 @@ public class MavenIndicesManager implements Disposable {
private volatile MavenIndices myIndices;
private final Object myUpdatingIndicesLock = new Object();
private final List<MavenIndex> myWaitingIndices = new ArrayList<>();
private volatile MavenIndex myUpdatingIndex;
private final List<MavenSearchIndex> myWaitingIndices = new ArrayList<>();
private volatile MavenSearchIndex myUpdatingIndex;
private final BackgroundTaskQueue myUpdatingQueue = new BackgroundTaskQueue(null, IndicesBundle.message("maven.indices.updating"));
private volatile List<MavenArchetype> myUserArchetypes = new ArrayList<>();
@@ -93,10 +93,12 @@ public class MavenIndicesManager implements Disposable {
};
MavenServerManager.getInstance().addDownloadListener(myDownloadListener);
myIndices = new MavenIndices(myIndexer, getIndicesDir().toFile(), new MavenIndex.IndexListener() {
myIndices = new MavenIndices(myIndexer, getIndicesDir().toFile(), new MavenSearchIndex.IndexListener() {
@Override
public void indexIsBroken(@NotNull MavenIndex index) {
scheduleUpdate(null, Collections.singletonList(index), false);
public void indexIsBroken(@NotNull MavenSearchIndex index) {
if(index instanceof MavenIndex) {
scheduleUpdate(null, Collections.singletonList((MavenIndex)index), false);
}
}
});
@@ -147,51 +149,35 @@ public class MavenIndicesManager implements Disposable {
return getIndicesObject().getIndices();
}
public synchronized List<MavenIndex> ensureIndicesExist(Project project,
File localRepository,
Collection<Pair<String, String>> remoteRepositoriesIdsAndUrls) {
// MavenIndices.add method returns an existing index if it has already been added, thus we have to use set here.
LinkedHashSet<MavenIndex> result = new LinkedHashSet<>();
MavenIndices indicesObjectCache = getIndicesObject();
public synchronized MavenIndex ensureRemoteIndexExist(Project project, Pair<String, String> remoteIndexIdAndUrl) {
try {
MavenIndex localIndex = indicesObjectCache.add(LOCAL_REPOSITORY_ID, localRepository.getPath(), MavenIndex.Kind.LOCAL);
result.add(localIndex);
if (localIndex.getUpdateTimestamp() == -1) {
scheduleUpdate(project, Collections.singletonList(localIndex));
}
MavenIndices indicesObjectCache = getIndicesObject();
return indicesObjectCache.add(remoteIndexIdAndUrl.first, remoteIndexIdAndUrl.second, MavenSearchIndex.Kind.REMOTE);
}
catch (MavenIndexException e) {
MavenLog.LOG.warn(e);
return null;
}
}
public synchronized List<MavenIndex> ensureIndicesExist(Project project,
Collection<Pair<String, String>> remoteRepositoriesIdsAndUrls) {
// MavenIndices.add method returns an existing index if it has already been added, thus we have to use set here.
LinkedHashSet<MavenIndex> result = new LinkedHashSet<>();
for (Pair<String, String> eachIdAndUrl : remoteRepositoriesIdsAndUrls) {
try {
MavenIndex remoteIndex = indicesObjectCache.add(eachIdAndUrl.first, eachIdAndUrl.second, MavenIndex.Kind.REMOTE);
result.add(remoteIndex);
if (!ApplicationManager.getApplication().isHeadlessEnvironment() &&
MavenProjectsManager.getInstance(project).getGeneralSettings().isUpdateIndicesOnProjectOpen() &&
remoteIndex.getUpdateTimestamp() < System.currentTimeMillis() - 3600 * 24 * 1000 &&
remoteIndex.getUpdateTimestamp() != -1) {
scheduleUpdate(project, Collections.singletonList(remoteIndex));
}
}
catch (MavenIndexException e) {
MavenLog.LOG.warn(e);
}
result.add(ensureRemoteIndexExist(project, eachIdAndUrl));
}
return new ArrayList<>(result);
}
private void addArtifact(File artifactFile, String relativePath) {
String repositoryPath = getRepositoryUrl(artifactFile, relativePath);
MavenIndex index = getIndicesObject().find(repositoryPath, MavenIndex.Kind.LOCAL);
if (index != null) {
index.addArtifact(artifactFile);
MavenSearchIndex index = getIndicesObject().find(repositoryPath, MavenSearchIndex.Kind.LOCAL);
if (index instanceof MavenIndex) {
((MavenIndex)index).addArtifact(artifactFile);
}
}
@@ -214,10 +200,10 @@ public class MavenIndicesManager implements Disposable {
}
private Promise<Void> scheduleUpdate(final Project projectOrNull, List<MavenIndex> indices, final boolean fullUpdate) {
final List<MavenIndex> toSchedule = new ArrayList<>();
final List<MavenSearchIndex> toSchedule = new ArrayList<>();
synchronized (myUpdatingIndicesLock) {
for (MavenIndex each : indices) {
for (MavenSearchIndex each : indices) {
if (myWaitingIndices.contains(each)) continue;
toSchedule.add(each);
}
@@ -246,14 +232,14 @@ public class MavenIndicesManager implements Disposable {
return promise;
}
private void doUpdateIndices(final Project projectOrNull, List<MavenIndex> indices, boolean fullUpdate, MavenProgressIndicator indicator)
private void doUpdateIndices(final Project projectOrNull, List<MavenSearchIndex> indices, boolean fullUpdate, MavenProgressIndicator indicator)
throws MavenProcessCanceledException {
MavenLog.LOG.assertTrue(!fullUpdate || projectOrNull != null);
List<MavenIndex> remainingWaiting = new ArrayList<>(indices);
List<MavenSearchIndex> remainingWaiting = new ArrayList<>(indices);
try {
for (MavenIndex each : indices) {
for (MavenSearchIndex each : indices) {
if (indicator.isCanceled()) return;
indicator.setText(IndicesBundle.message("maven.indices.updating.index",
@@ -302,7 +288,7 @@ public class MavenIndicesManager implements Disposable {
return settings;
}
public IndexUpdatingState getUpdatingState(MavenIndex index) {
public IndexUpdatingState getUpdatingState(MavenSearchIndex index) {
synchronized (myUpdatingIndicesLock) {
if (myUpdatingIndex == index) return IndexUpdatingState.UPDATING;
if (myWaitingIndices.contains(index)) return IndexUpdatingState.WAITING;
@@ -314,8 +300,10 @@ public class MavenIndicesManager implements Disposable {
ensureInitialized();
Set<MavenArchetype> result = new THashSet<>(myIndexer.getArchetypes());
result.addAll(myUserArchetypes);
for (MavenIndex index : myIndices.getIndices()) {
result.addAll(index.getArchetypes());
for (MavenSearchIndex index : myIndices.getIndices()) {
if (index instanceof MavenIndex) {
result.addAll(((MavenIndex)index).getArchetypes());
}
}
for (MavenArchetypesProvider each : MavenArchetypesProvider.EP_NAME.getExtensionList()) {
@@ -33,6 +33,12 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.model.MavenId;
import org.jetbrains.idea.maven.model.MavenRemoteRepository;
import org.jetbrains.idea.maven.onlinecompletion.DependencyCompletionProvider;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.onlinecompletion.IndexBasedSearchService;
import org.jetbrains.idea.maven.onlinecompletion.LocalCompletionSearch;
import org.jetbrains.idea.maven.onlinecompletion.central.MavenCentralOnlineSearch;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.project.MavenProject;
import org.jetbrains.idea.maven.project.MavenProjectChanges;
import org.jetbrains.idea.maven.project.MavenProjectsManager;
@@ -42,15 +48,19 @@ import org.jetbrains.idea.maven.utils.MavenMergingUpdateQueue;
import org.jetbrains.idea.maven.utils.MavenSimpleProjectComponent;
import java.io.File;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
public class MavenProjectIndicesManager extends MavenSimpleProjectComponent implements BaseComponent {
private volatile List<MavenIndex> myProjectIndices = new ArrayList<>();
private volatile boolean offlineIndexes = false;
private volatile DependencySearchService mySearchService = new DependencySearchService(Collections.EMPTY_LIST);
private final MergingUpdateQueue myUpdateQueue;
public boolean hasOfflineIndexes() {
return offlineIndexes;
}
public static MavenProjectIndicesManager getInstance(Project p) {
return p.getComponent(MavenProjectIndicesManager.class);
}
@@ -92,6 +102,9 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
});
}
public void scheduleUpdateRepositoryList() {
scheduleUpdateIndicesList();
}
private void scheduleUpdateIndicesList() {
scheduleUpdateIndicesList(null);
}
@@ -107,9 +120,36 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
remoteRepositoriesIdsAndUrls = ReadAction.compute(() -> myProject.isDisposed() ? null : collectRemoteRepositoriesIdsAndUrls());
localRepository = ReadAction.compute(() -> myProject.isDisposed() ? null : getLocalRepository());
if (remoteRepositoriesIdsAndUrls == null || localRepository == null) return;
Set<DependencyCompletionProvider> providers = new HashSet<>();
providers.add(new LocalCompletionSearch(localRepository));
List<MavenIndex> newIndices = new ArrayList<>();
myProjectIndices = MavenIndicesManager.getInstance().ensureIndicesExist(myProject, localRepository, remoteRepositoriesIdsAndUrls);
if(consumer != null) {
Iterator<Pair<String, String>> iterator = remoteRepositoriesIdsAndUrls.iterator();
while (iterator.hasNext()) {
Pair<String, String> pair = iterator.next();
if (pair.second.contains("repo.maven.apache.org/maven2") || "central".equals(pair.first)) {
providers.add(new MavenCentralOnlineSearch());
iterator.remove();
}
}
List<MavenIndex> offlineIndices =
MavenIndicesManager.getInstance().ensureIndicesExist(myProject, remoteRepositoriesIdsAndUrls);
for (MavenSearchIndex index : offlineIndices) {
if (index instanceof MavenIndex) {
providers.add(new IndexBasedSearchService((MavenIndex)index));
}
}
newIndices.addAll(offlineIndices);
synchronized (this) {
offlineIndexes = !remoteRepositoriesIdsAndUrls.isEmpty();
myProjectIndices = newIndices;
mySearchService = new DependencySearchService(new ArrayList<>(providers));
}
if (consumer != null) {
consumer.consume(myProjectIndices);
}
}
@@ -135,6 +175,8 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
return result;
}
@Deprecated
/* @deprecated use getSearchService */
public List<MavenIndex> getIndices() {
return new ArrayList<>(myProjectIndices);
}
@@ -147,7 +189,7 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
MavenIndicesManager.getInstance().scheduleUpdate(myProject, indices);
}
public MavenIndicesManager.IndexUpdatingState getUpdatingState(MavenIndex index) {
public MavenIndicesManager.IndexUpdatingState getUpdatingState(MavenSearchIndex index) {
return MavenIndicesManager.getInstance().getUpdatingState(index);
}
@@ -155,39 +197,49 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
return MavenProjectsManager.getInstance(myProject);
}
public Set<String> getGroupIds() {
ProgressIndicatorProvider.checkCanceled();
Set<String> result = getProjectGroupIds();
for (MavenIndex each : myProjectIndices) {
result.addAll(each.getGroupIds());
}
return result;
public synchronized DependencySearchService getSearchService() {
return mySearchService;
}
@Deprecated
/** @deprecated use {@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findGroupCandidates} or{@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findByTemplate} instead**/
public Set<String> getGroupIds() {
return getGroupIds("");
}
@Deprecated
/** @deprecated use {@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findGroupCandidates} or{@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findByTemplate} instead**/
public Set<String> getGroupIds(String pattern) {
pattern = pattern == null ? "" : pattern;
//todo fix
return getSearchService().findGroupCandidates(new MavenDependencyCompletionItem(pattern))
.stream().map(d -> d.getArtifactId())
.collect(
Collectors.toSet());
}
@Deprecated
/** @deprecated use {@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findArtifactCandidates} or{@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findByTemplate} instead**/
public Set<String> getArtifactIds(String groupId) {
ProgressIndicatorProvider.checkCanceled();
Set<String> result = getProjectArtifactIds(groupId);
for (MavenIndex each : myProjectIndices) {
result.addAll(each.getArtifactIds(groupId));
}
return result;
return getSearchService().findArtifactCandidates(new MavenDependencyCompletionItem(groupId)).stream().map(d -> d.getArtifactId())
.collect(
Collectors.toSet());
}
/**
* @deprecated use {@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findAllVersions or{@link org.jetbrains.idea.maven.onlinecompletion.DependencySearchService#findByTemplate} instead
**/
public Set<String> getVersions(String groupId, String artifactId) {
ProgressIndicatorProvider.checkCanceled();
Set<String> result = getProjectVersions(groupId, artifactId);
for (MavenIndex each : myProjectIndices) {
result.addAll(each.getVersions(groupId, artifactId));
}
return result;
return getSearchService().findAllVersions(new MavenDependencyCompletionItem(groupId, artifactId, null, null)).stream()
.map(d -> d.getArtifactId()).collect(
Collectors.toSet());
}
@Deprecated
public boolean hasGroupId(String groupId) {
if (hasProjectGroupId(groupId)) return true;
for (MavenIndex each : myProjectIndices) {
if (each.hasGroupId(groupId)) return true;
}
return checkLocalRepository(groupId, null, null);
return !getSearchService().findGroupCandidates(new MavenDependencyCompletionItem(groupId)).isEmpty();
}
private boolean checkLocalRepository(String groupId, String artifactId, String version) {
@@ -206,32 +258,21 @@ public class MavenProjectIndicesManager extends MavenSimpleProjectComponent impl
return file.exists();
}
@Deprecated
public boolean hasArtifactId(String groupId, String artifactId) {
if (hasProjectArtifactId(groupId, artifactId)) return true;
for (MavenIndex each : myProjectIndices) {
if (each.hasArtifactId(groupId, artifactId)) return true;
}
return checkLocalRepository(groupId, artifactId, null);
return !getSearchService().findAllVersions(new MavenDependencyCompletionItem(groupId, artifactId, null, null)).isEmpty();
}
@Deprecated
public boolean hasVersion(String groupId, String artifactId, String version) {
if (hasProjectVersion(groupId, artifactId, version)) return true;
for (MavenIndex each : myProjectIndices) {
if (each.hasVersion(groupId, artifactId, version)) return true;
}
return checkLocalRepository(groupId, artifactId, version);
return getSearchService().findAllVersions(new MavenDependencyCompletionItem(groupId, artifactId, null, null)).stream().anyMatch(
s -> version.equals(s.getVersion())
);
}
public Set<MavenArtifactInfo> search(Query query, int maxResult) {
Set<MavenArtifactInfo> result = new THashSet<>();
for (MavenIndex each : myProjectIndices) {
int remained = maxResult - result.size();
if (remained <= 0) break;
result.addAll(each.search(query, remained));
}
return result;
//TODO
return Collections.emptySet();
}
private Set<String> getProjectGroupIds() {
@@ -28,6 +28,8 @@ import java.awt.event.MouseMotionListener;
import java.util.ArrayList;
import java.util.List;
import static org.jetbrains.idea.maven.indices.MavenSearchIndex.Kind.REMOTE;
public class MavenRepositoriesConfigurable implements SearchableConfigurable, Configurable.NoScroll {
private final MavenProjectIndicesManager myManager;
@@ -88,11 +90,12 @@ public class MavenRepositoriesConfigurable implements SearchableConfigurable, Co
private void updateButtonsState() {
boolean hasSelection = !myIndicesTable.getSelectionModel().isSelectionEmpty();
hasSelection = getSelectedIndices().stream().anyMatch(i -> i.getKind() == REMOTE);
myUpdateButton.setEnabled(hasSelection);
}
public void updateIndexHint(int row) {
MavenIndex index = getIndexAt(row);
MavenSearchIndex index = getIndexAt(row);
String message = index.getFailureMessage();
if (message == null) {
myIndicesTable.setToolTipText(null);
@@ -211,12 +214,13 @@ public class MavenRepositoriesConfigurable implements SearchableConfigurable, Co
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
MavenIndex i = getIndex(rowIndex);
MavenSearchIndex i = getIndex(rowIndex);
switch (columnIndex) {
case 0:
return i.getRepositoryPathOrUrl();
case 1:
if (i.getKind() == MavenIndex.Kind.LOCAL) return "Local";
if (i.getKind() == MavenSearchIndex.Kind.LOCAL) return "Local";
if (i.getKind() == MavenSearchIndex.Kind.ONLINE) return "Online";
return "Remote";
case 2:
if (i.getFailureMessage() != null) {
@@ -224,6 +228,7 @@ public class MavenRepositoriesConfigurable implements SearchableConfigurable, Co
}
long timestamp = i.getUpdateTimestamp();
if (timestamp == -1) return IndicesBundle.message("maven.index.updated.never");
if (i.getKind() != REMOTE) return IndicesBundle.message("maven.index.updated.notapplicable");
return DateFormatUtil.formatDate(timestamp);
case 3:
return myManager.getUpdatingState(i);
@@ -245,7 +250,7 @@ public class MavenRepositoriesConfigurable implements SearchableConfigurable, Co
Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
MavenIndex index = getIndexAt(row);
MavenSearchIndex index = getIndexAt(row);
if (index.getFailureMessage() != null) {
if (isSelected) {
setForeground(JBColor.PINK);
@@ -0,0 +1,57 @@
/*
* Copyright 2000-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.maven.indices;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.project.MavenGeneralSettings;
import org.jetbrains.idea.maven.utils.MavenProcessCanceledException;
import org.jetbrains.idea.maven.utils.MavenProgressIndicator;
import java.io.File;
public interface MavenSearchIndex {
enum Kind {
LOCAL, REMOTE, ONLINE
}
void registerId(String repositoryId) throws MavenIndexException;
void close(boolean releaseIndexContext);
String getRepositoryId();
File getRepositoryFile();
String getRepositoryUrl();
String getRepositoryPathOrUrl();
Kind getKind();
boolean isFor(Kind kind, String pathOrUrl);
long getUpdateTimestamp();
String getFailureMessage();
void updateOrRepair(boolean fullUpdate, MavenGeneralSettings settings, MavenProgressIndicator progress)
throws MavenProcessCanceledException;
interface IndexListener {
void indexIsBroken(@NotNull MavenSearchIndex index);
}
}
@@ -17,7 +17,7 @@ package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.project.Project;
import org.jetbrains.idea.maven.dom.MavenVersionComparable;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.*;
@@ -32,27 +32,23 @@ public abstract class MavenSearcher<RESULT_TYPE extends MavenArtifactSearchResul
private List<RESULT_TYPE> sort(List<RESULT_TYPE> result) {
for (RESULT_TYPE each : result) {
if (each.versions.size() > 1) {
TreeMap<MavenVersionComparable, MavenArtifactInfo> tree = new TreeMap<>(Collections.reverseOrder());
TreeMap<MavenVersionComparable, MavenDependencyCompletionItem> tree = new TreeMap<>(Collections.reverseOrder());
for (MavenArtifactInfo artifactInfo : each.versions) {
for (MavenDependencyCompletionItem artifactInfo : each.getSearchResults()) {
tree.put(new MavenVersionComparable(artifactInfo.getVersion()), artifactInfo);
}
each.versions.clear();
each.versions.addAll(tree.values());
each.setResults(new ArrayList<>(tree.values()));
}
}
Collections.sort(result, Comparator.comparing(this::makeSortKey));
return result;
}
protected String makeSortKey(RESULT_TYPE result) {
return makeKey(result.versions.get(0));
return makeKey(result.getSearchResults().get(0));
}
protected String makeKey(MavenArtifactInfo result) {
protected String makeKey(MavenDependencyCompletionItem result) {
return result.getGroupId() + ":" + result.getArtifactId();
}
}
@@ -0,0 +1,74 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.indices;
import org.jetbrains.idea.maven.project.MavenGeneralSettings;
import org.jetbrains.idea.maven.utils.MavenProcessCanceledException;
import org.jetbrains.idea.maven.utils.MavenProgressIndicator;
import java.io.File;
/*this class used only for backward compatibility for legacy code, which expect to get MavenIndices. To be removed in future releases*/
public class OnlineMavenIndex implements MavenSearchIndex {
private final String myRepositoryId;
private final String myRepositoryUrl;
public OnlineMavenIndex(String repositoryId, String repositoryUrl) {
myRepositoryId = repositoryId;
myRepositoryUrl = repositoryUrl;
}
@Override
public void registerId(String repositoryId) throws MavenIndexException {
}
@Override
public void close(boolean releaseIndexContext) {
}
@Override
public String getRepositoryId() {
return myRepositoryId;
}
@Override
public File getRepositoryFile() {
return null;
}
@Override
public String getRepositoryUrl() {
return myRepositoryUrl;
}
@Override
public String getRepositoryPathOrUrl() {
return myRepositoryUrl;
}
@Override
public Kind getKind() {
return Kind.ONLINE;
}
@Override
public boolean isFor(Kind kind, String pathOrUrl) {
return kind == Kind.ONLINE && myRepositoryUrl.equals(pathOrUrl);
}
@Override
public long getUpdateTimestamp() {
return -1;
}
@Override
public String getFailureMessage() {
return null;
}
@Override
public void updateOrRepair(boolean fullUpdate, MavenGeneralSettings settings, MavenProgressIndicator progress)
throws MavenProcessCanceledException {
}
}
@@ -0,0 +1,73 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collector;
class DeduplicationCollector<Result extends MavenDependencyCompletionItem>
implements
Collector<List<? extends Result>, Map<String, Result>, List<Result>> {
static final Set<Characteristics> CHARACTERISTICS
= Collections.unmodifiableSet(EnumSet.of(Characteristics.UNORDERED));
private final Function<Result, String> myDeduplicationKey;
DeduplicationCollector(Function<Result, String> deduplicationKey) {
myDeduplicationKey = deduplicationKey;
}
@Override
public Supplier<Map<String, Result>> supplier() {
return () -> new HashMap<>();
}
@Override
public BiConsumer<Map<String, Result>, List<? extends Result>> accumulator() {
return (m, l) -> {
if (l != null && m != null) {
for (Result item : l) {
String key = myDeduplicationKey.apply(item);
Result present = m.get(key);
if (present == null || present.getType().getWeight() < item.getType().getWeight()) {
m.put(key, item);
}
}
}
};
}
@Override
public BinaryOperator<Map<String, Result>> combiner() {
return (m, l) -> {
for (Result item : l.values()) {
String key = myDeduplicationKey.apply(item);
Result present = m.get(key);
if (present != null && item.getType() == null) {
continue;
}
if (present == null ||
present.getType() == null && item.getType() != null ||
present.getType().getWeight() < item.getType().getWeight()) {
m.put(key, item);
}
}
return m;
};
}
@Override
public Function<Map<String, Result>, List<Result>> finisher() {
return m -> new ArrayList<>(m.values());
}
@Override
public Set<Characteristics> characteristics() {
return CHARACTERISTICS;
}
}
@@ -0,0 +1,31 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenCoordinate;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import java.io.IOException;
import java.util.List;
public interface DependencyCompletionProvider {
@NotNull
List<MavenDependencyCompletionItem> findGroupCandidates(MavenCoordinate template, SearchParameters searchParameters)
throws IOException;
@NotNull
List<MavenDependencyCompletionItem> findArtifactCandidates(MavenCoordinate template, SearchParameters searchParameters)
throws IOException;
@NotNull
List<MavenDependencyCompletionItem> findAllVersions(MavenCoordinate template, SearchParameters searchParameters)
throws IOException;
@NotNull
List<MavenDependencyCompletionItemWithClass> findClassesByString(String str, SearchParameters searchParameters)
throws IOException;
}
@@ -0,0 +1,139 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;
import org.jetbrains.idea.maven.model.MavenCoordinate;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import org.jetbrains.idea.maven.utils.MavenLog;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.stream.Collector;
public class DependencySearchService {
private static final DeduplicationCollector<MavenDependencyCompletionItem> GROUP_COLLECTOR =
new DeduplicationCollector<>(m -> m.getGroupId());
private static final DeduplicationCollector<MavenDependencyCompletionItem> ARTIFACT_COLLECTOR =
new DeduplicationCollector<>(m -> m.getGroupId() + ":" + m.getArtifactId());
private static final DeduplicationCollector VERSION_COLLECTOR =
new DeduplicationCollector<>(m -> m.getGroupId() + ":" + m.getArtifactId() + ":" + m.getVersion());
private final List<DependencyCompletionProvider> myProviders;
public DependencySearchService(List<DependencyCompletionProvider> providers) {
myProviders = providers;
}
@NotNull
public List<MavenDependencyCompletionItem> findByTemplate(@NotNull String coord) {
return findByTemplate(coord, SearchParameters.DEFAULT);
}
@NotNull
public List<MavenDependencyCompletionItem> findByTemplate(@NotNull String coord, @NotNull SearchParameters parameters) {
MavenDependencyCompletionItem template = new MavenDependencyCompletionItem(coord, null);
if (StringUtil.isEmpty(template.getGroupId())) {
return Collections.emptyList();
}
else if (StringUtil.isEmpty(template.getArtifactId())) {
List<MavenDependencyCompletionItem> result = new ArrayList<>();
result.addAll(findGroupCandidates(template, parameters));
result.addAll(findArtifactCandidates(template, parameters));
return result;
}
else if (StringUtil.isEmpty(template.getVersion())) {
List<MavenDependencyCompletionItem> result = new ArrayList<>();
result.addAll(findArtifactCandidates(template, parameters));
result.addAll(findAllVersions(template, parameters));
return result;
}
return findAllVersions(template, parameters);
}
@NotNull
public List<MavenDependencyCompletionItem> findGroupCandidates(@NotNull MavenCoordinate template) {
return findGroupCandidates(template, SearchParameters.DEFAULT);
}
public List<MavenDependencyCompletionItem> findGroupCandidates(@NotNull MavenCoordinate template, @NotNull SearchParameters parameters) {
return doQuery(parameters, template, (p, s) -> p.findGroupCandidates(s, parameters), GROUP_COLLECTOR);
}
@NotNull
public List<MavenDependencyCompletionItem> findArtifactCandidates(@NotNull MavenCoordinate template) {
return findArtifactCandidates(template, SearchParameters.DEFAULT);
}
@NotNull
public List<MavenDependencyCompletionItem> findArtifactCandidates(@NotNull MavenCoordinate template,
@NotNull SearchParameters parameters) {
return doQuery(parameters, template, (p, s) -> p.findArtifactCandidates(s, parameters), ARTIFACT_COLLECTOR);
}
@NotNull
public List<MavenDependencyCompletionItem> findAllVersions(@NotNull MavenCoordinate template) {
return findAllVersions(template, SearchParameters.DEFAULT);
}
@NotNull
public List<MavenDependencyCompletionItem> findAllVersions(@NotNull MavenCoordinate template, @NotNull SearchParameters parameters) {
return doQuery(parameters, template, (p, s) -> p.findAllVersions(s, parameters), VERSION_COLLECTOR);
}
@NotNull
public List<MavenDependencyCompletionItemWithClass> findClasses(@NotNull String className) {
return findClasses(className, SearchParameters.DEFAULT);
}
@NotNull
public List<MavenDependencyCompletionItemWithClass> findClasses(@NotNull String className, @NotNull SearchParameters parameters) {
return doQuery(parameters, className, (p, s) -> p.findClassesByString(s, parameters), VERSION_COLLECTOR);
}
private <PARAM, RESULT extends MavenDependencyCompletionItem> List<RESULT> doQuery(@NotNull SearchParameters parameters,
PARAM template,
ThrowingSearch<PARAM, RESULT> search,
Collector<? super List<RESULT>, ?, List<RESULT>> collector) {
final Application application = ApplicationManager.getApplication();
return myProviders
.stream().map(provider -> application.executeOnPooledThread(
() -> search.search(provider, template)))
.map(f -> {
try {
return f.get(parameters.getMillisToWait(), TimeUnit.MILLISECONDS);
}
catch (InterruptedException | ExecutionException | TimeoutException e) {
if (application.isInternal()) {
MavenLog.LOG.error(e);
}
else {
MavenLog.LOG.debug(e);
}
return Collections.<RESULT>emptyList();
}
}).collect(collector);
}
@FunctionalInterface
private interface ThrowingSearch<PARAM, RESULT extends MavenDependencyCompletionItem> {
List<RESULT> search(DependencyCompletionProvider p, PARAM t) throws IOException;
}
@TestOnly
public List<DependencyCompletionProvider> getProviders() {
return myProviders;
}
}
@@ -0,0 +1,87 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.containers.ContainerUtil;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.queryParser.ParseException;
import org.apache.lucene.queryParser.QueryParser;
import org.apache.lucene.search.Query;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.indices.MavenSearchIndex;
import org.jetbrains.idea.maven.indices.MavenIndex;
import org.jetbrains.idea.maven.model.MavenCoordinate;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import org.jetbrains.idea.maven.utils.MavenLog;
import java.io.IOException;
import java.util.Collections;
import java.util.List;
/**
* This class is used as a solution to support completion from repositories, which do not support online completion
*/
public class IndexBasedSearchService implements DependencyCompletionProvider {
private final MavenIndex myIndex;
public IndexBasedSearchService(MavenIndex index) {myIndex = index;}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findGroupCandidates(MavenCoordinate template, SearchParameters parameters) throws IOException {
return ContainerUtil.map(myIndex.getGroupIds(), g -> new MavenDependencyCompletionItem(g, MavenDependencyCompletionItem.Type.REMOTE));
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findArtifactCandidates(MavenCoordinate template, SearchParameters parameters) throws IOException {
return ContainerUtil.map(myIndex.getArtifactIds(template.getGroupId()), a ->
new MavenDependencyCompletionItem(template.getGroupId(), a, null, MavenDependencyCompletionItem.Type.REMOTE));
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findAllVersions(MavenCoordinate template, SearchParameters parameters) throws IOException {
return ContainerUtil.map(myIndex.getVersions(template.getGroupId(), template.getArtifactId()), v ->
new MavenDependencyCompletionItem(template.getGroupId(), template.getArtifactId(), v, MavenDependencyCompletionItem.Type.REMOTE));
}
@NotNull
@Override
public List<MavenDependencyCompletionItemWithClass> findClassesByString(@NotNull String str, SearchParameters parameters) {
if (StringUtil.isEmpty(str)) {
return Collections.emptyList();
}
Query searchQuery = null;
try {
searchQuery = createSearchQuery(str);
}
catch (ParseException e) {
MavenLog.LOG.debug(e);
return Collections.emptyList();
}
return ContainerUtil.map(myIndex.search(searchQuery, parameters.getMaxResults()),
r -> new MavenDependencyCompletionItemWithClass(r.getGroupId(), r.getArtifactId(), r.getVersion(),
MavenDependencyCompletionItem.Type.LOCAL,
Collections.singletonList(r.getClassNames())));
}
private static Query createSearchQuery(@NotNull String str) throws ParseException {
String[] patterns = str.split("\\.");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < patterns.length; i++) {
builder.append("c:").append(patterns[i]).append(" OR ");
}
builder.append("fc:").append(str);
return new QueryParser("c", new StandardAnalyzer()).parse(builder.toString());
}
public MavenSearchIndex getIndex() {
return myIndex;
}
}
@@ -0,0 +1,142 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.hash.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.model.MavenCoordinate;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import java.io.File;
import java.io.IOException;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem.Type.CACHED_ERROR;
import static org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem.Type.LOCAL;
public class LocalCompletionSearch implements DependencyCompletionProvider {
private final Path myLocalRepo;
private static final PathMatcher groupMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*/*");
private static final PathMatcher pomMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.pom");
private static final PathMatcher errorUpdatedMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.lastUpdated");
private static final PathMatcher versionMatcher = FileSystems.getDefault().getPathMatcher("glob:**/*.*");
public LocalCompletionSearch(File localRepo) {
myLocalRepo = localRepo.toPath();
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findGroupCandidates(MavenCoordinate template, SearchParameters parameters) throws IOException {
Set<String> collected = new HashSet<>();
Files.walkFileTree(myLocalRepo, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult preVisitDirectory(Path file, BasicFileAttributes attrs) throws IOException {
boolean isVersion = versionMatcher.matches(file);
if (isVersion && attrs.isDirectory()) {
String parentRelativePath = myLocalRepo.relativize(file.getParent().getParent()).toString();
collected.add(parentRelativePath.replace(File.separatorChar, '.'));
return FileVisitResult.SKIP_SUBTREE;
}
return FileVisitResult.CONTINUE;
}
});
if (parameters.getFlags().contains(SearchParameters.Flags.FULL_RESOLVE)) {
return collected.stream().flatMap(
g -> {
try {
return findArtifactCandidates(new MavenDependencyCompletionItem(g, LOCAL), parameters).stream();
}
catch (IOException e) {
return Stream.empty();
}
}).collect(Collectors.toList());
}
return ContainerUtil.map(collected, g -> new MavenDependencyCompletionItem(g, LOCAL));
}
;
@NotNull
@Override
public List<MavenDependencyCompletionItem> findArtifactCandidates(MavenCoordinate template, SearchParameters parameters)
throws IOException {
if (template.getGroupId() == null || template.getGroupId().isEmpty()) {
return Collections.emptyList();
}
File[] files = myLocalRepo.resolve(template.getGroupId().replace('.', File.separatorChar)).toFile().listFiles();
if (files == null || files.length == 0) {
return Collections.emptyList();
}
if (parameters.getFlags().contains(SearchParameters.Flags.FULL_RESOLVE)) {
return Arrays.stream(files).flatMap(
f -> {
try {
return findAllVersions(new MavenDependencyCompletionItem(template.getGroupId(), f.getName(), null, LOCAL), parameters).stream();
}
catch (IOException e) {
return Stream.empty();
}
}).collect(Collectors.toList());
}
return ContainerUtil.map(files, f -> new MavenDependencyCompletionItem(template.getGroupId(), f.getName(), null, LOCAL));
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findAllVersions(MavenCoordinate template, SearchParameters parameters) throws IOException {
if (template.getGroupId() == null || template.getGroupId().isEmpty()
|| template.getArtifactId() == null || template.getArtifactId().isEmpty()) {
return Collections.emptyList();
}
Path artifactDir = myLocalRepo.resolve(template.getGroupId().replace('.', File.separatorChar)).resolve(template.getArtifactId());
if (!artifactDir.toFile().exists()) {
return Collections.emptyList();
}
List<MavenDependencyCompletionItem> result = new ArrayList<>();
Files.walkFileTree(artifactDir, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Path versionDir = file.getParent();
String version = versionDir.toFile().getName();
if (errorUpdatedMatcher.matches(file) && attrs.isRegularFile()) {
result.add(new MavenDependencyCompletionItem(template.getGroupId(), template.getArtifactId(), version, CACHED_ERROR));
return FileVisitResult.SKIP_SIBLINGS;
}
if (pomMatcher.matches(file) && attrs.isRegularFile()) {
result.add(new MavenDependencyCompletionItem(template.getGroupId(), template.getArtifactId(), version, LOCAL));
return FileVisitResult.SKIP_SIBLINGS;
}
return FileVisitResult.CONTINUE;
}
});
return result;
}
@NotNull
@Override
public List<MavenDependencyCompletionItemWithClass> findClassesByString(String str, SearchParameters parameters) {
return Collections.emptyList();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LocalCompletionSearch search = (LocalCompletionSearch)o;
return FileUtil.filesEqual(myLocalRepo.toFile(), search.myLocalRepo.toFile());
}
@Override
public int hashCode() {
return FileUtil.fileHashCode(myLocalRepo.toFile());
}
}
@@ -0,0 +1,21 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
public final class MavenScopeTable {
private MavenScopeTable() {}
public static String getUsualScope(MavenDependencyCompletionItem item) {
String groupId = item.getGroupId();
if (groupId == null) {
return null;
}
if (groupId.contains("junit") || groupId.equals("org.mockito") || groupId.equals("org.hamcrest")) {
return "test";
}
return null;
}
}
@@ -0,0 +1,77 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion.central;
import com.google.gson.*;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class MavenCentralModel {
public ResponseHeader responseHeader;
public Response response;
public Highlighting highlighting;
public static class ResponseHeader {
public int status;
}
public static class Response {
public int numFound;
public int start;
public FoundDoc[] docs;
public Highlighting highlighting;
public static class FoundDoc {
public String id;
public String g; //group
public String a; //artifactId
public String v; //version
public String latestVersion;
public String repositoryId;
public String p; //packaging
public int versionCount;
public long timestamp;
}
}
public static class Highlighting {
public List<MavenDependencyCompletionItemWithClass> results;
}
public static class HighlightingDeserializer implements JsonDeserializer<Highlighting> {
@Override
public Highlighting deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
if (json == null) {
return null;
}
JsonObject object = json.getAsJsonObject();
Highlighting result = new Highlighting();
result.results = ContainerUtil.newArrayListWithCapacity(object.size());
for (Map.Entry<String, JsonElement> entry : object.entrySet()) {
JsonArray fch = entry.getValue().getAsJsonObject().get("fch").getAsJsonArray();
String[] hightlights = new String[fch.size()];
for (int i = 0; i < hightlights.length; i++) {
hightlights[i] = clearEM(fch.get(i).getAsString());
}
result.results.add(new MavenDependencyCompletionItemWithClass(entry.getKey(), MavenDependencyCompletionItem.Type.REMOTE,
ContainerUtil.newArrayList(hightlights)));
}
return result;
}
private static String clearEM(String string) {
return string.replaceAll("<em>", "").replaceAll("</em>", "");
}
}
}
@@ -0,0 +1,195 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion.central;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.io.HttpRequests;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.model.MavenCoordinate;
import org.jetbrains.idea.maven.onlinecompletion.DependencyCompletionProvider;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItemWithClass;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import static org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters.Flags.ALL_VERSIONS;
public class MavenCentralOnlineSearch implements DependencyCompletionProvider {
private static final String DEFAULT_SEARCH_URI = "https://search.maven.org/solrsearch/select?q=";
private final static int MIN_LENGTH = 2;
private final Gson myGson;
private final String mySearchUrl;
public static final String UTF8 = StandardCharsets.UTF_8.toString();
public MavenCentralOnlineSearch() {
myGson = new GsonBuilder()
.registerTypeAdapter(MavenCentralModel.Highlighting.class, new MavenCentralModel.HighlightingDeserializer())
.create();
mySearchUrl = DEFAULT_SEARCH_URI;
}
@NotNull
public String getDisplayName() {
return "Maven Central";
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findGroupCandidates(MavenCoordinate template, SearchParameters parameters) throws IOException {
if (StringUtil.isEmpty(template.getGroupId())) {
return Collections.emptyList();
}
String param = join(StringUtil.split(template.getGroupId(), "."));
if (param.isEmpty()) {
return Collections.emptyList();
}
String uri = createSearchUrl(param, parameters);
return convert(doRequest(uri));
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findArtifactCandidates(@NotNull MavenCoordinate template, SearchParameters parameters)
throws IOException {
if (template.getGroupId() == null) {
return findGroupCandidates(new MavenDependencyCompletionItem(template.getArtifactId()), parameters);
}
String param = template.getArtifactId() == null
? template.getGroupId()
: template.getGroupId() + join(StringUtil.split(template.getArtifactId(), "-"));
//we cannot query with GAV for maven search
EnumSet<SearchParameters.Flags> newFlags = parameters.getFlags().clone();
newFlags.remove(ALL_VERSIONS);
SearchParameters newParameters = new SearchParameters(parameters.getMaxResults(), parameters.getMillisToWait(), newFlags);
String uri = createSearchUrl(param, newParameters);
return convert(doRequest(uri));
}
@NotNull
@Override
public List<MavenDependencyCompletionItem> findAllVersions(MavenCoordinate template, SearchParameters parameters) throws IOException {
if (template.getArtifactId() == null) {
return findArtifactCandidates(template, parameters);
}
String uri = createSearchUrl("g:\"" + template.getGroupId() + "\" AND a:\"" + template.getArtifactId() + "\"", parameters);
return convert(doRequest(uri));
}
@NotNull
@Override
public List<MavenDependencyCompletionItemWithClass> findClassesByString(String str, SearchParameters parameters) throws IOException {
String uri = createSearchUrl(createSearchQuery(str), parameters);
MavenCentralModel model = doRequest(uri);
if (model == null || model.highlighting == null || model.highlighting.results == null) {
return Collections.emptyList();
}
return model.highlighting.results;
}
private static String createSearchQuery(@NotNull String str) {
String[] patterns = str.split("\\.");
StringBuilder builder = new StringBuilder();
for (int i = 0; i < patterns.length; i++) {
builder.append("c:").append("\"").append(patterns[i]).append("\"").append(" OR ");
}
builder.append("fc:").append(str);
return builder.toString();
}
private MavenCentralModel doRequest(String uri) throws IOException {
if (uri == null) {
return null;
}
ProgressManager.checkCanceled();
return HttpRequests.request(uri)
.productNameAsUserAgent()
.forceHttps(false)
.connect(request -> {
try {
String s = request.readString(null);
return myGson.fromJson(s, MavenCentralModel.class);
}
catch (HttpRequests.HttpStatusException ignored) {
return null;
}
});
}
private static String join(List<String> splitted) {
if(splitted.isEmpty()) {
return "";
}
StringBuilder builder = new StringBuilder();
for (String value : splitted) {
if (value.length() >= MIN_LENGTH) builder.append(value);
builder.append(' ');
}
if (builder.charAt(builder.length() - 1) == ' ') builder.deleteCharAt(builder.length() - 1);
return builder.toString();
}
@NotNull
private static List<MavenDependencyCompletionItem> convert(MavenCentralModel model) {
if (model == null ||
model.responseHeader.status != 0 ||
model.response == null ||
model.response.docs == null ||
model.response.docs.length == 0) {
return Collections.emptyList();
}
List<MavenDependencyCompletionItem> result = new ArrayList<>();
for (MavenCentralModel.Response.FoundDoc doc : model.response.docs) {
MavenDependencyCompletionItem description = new MavenDependencyCompletionItem(
doc.g,
doc.a,
doc.v == null ? doc.latestVersion : doc.v,
doc.p,
null,
MavenDependencyCompletionItem.Type.REMOTE);
result.add(description);
}
return result;
}
@Nullable
private String createSearchUrl(String queryParam, SearchParameters parameters) {
int rows = parameters.getMaxResults() < 20 ? 20 : parameters.getMaxResults();
String gav = parameters.getFlags().contains(ALL_VERSIONS) ? "&core=gav" : "";
try {
return mySearchUrl + URLEncoder.encode(queryParam, UTF8) + "&rows=" + rows + "&wt=json" + gav;
}
catch (UnsupportedEncodingException neverHappens) {
return null;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MavenCentralOnlineSearch search = (MavenCentralOnlineSearch)o;
return Objects.equals(mySearchUrl, search.mySearchUrl);
}
@Override
public int hashCode() {
return Objects.hash(mySearchUrl);
}
}
@@ -0,0 +1,75 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion.model;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.idea.maven.model.MavenId;
public class MavenDependencyCompletionItem extends MavenId {
private final Type myType;
private final String packaging;
private final String classifier;
public enum Type {
REMOTE(10), LOCAL(20), CACHED_ERROR(-1);
private final int myWeight;
Type(int weight) {myWeight = weight;}
public int getWeight() {
return myWeight;
}
}
public MavenDependencyCompletionItem(@Nullable String groupId,
@Nullable String artifactId,
@Nullable String version,
@Nullable String packaging,
@Nullable String classifier,
@Nullable Type type) {
super(groupId, artifactId, version);
myType = type;
this.packaging = packaging;
this.classifier = classifier;
}
public MavenDependencyCompletionItem(@Nullable String groupId,
@Nullable String artifactId,
@Nullable String version,
@Nullable Type type) {
this(groupId, artifactId, version, null, null, type);
}
public MavenDependencyCompletionItem(@Nullable String groupId,
@Nullable String artifactId,
@Nullable String version) {
this(groupId, artifactId, version, null, null, null);
}
public MavenDependencyCompletionItem(@Nullable String coord, @Nullable Type type) {
super(coord);
packaging = null;
classifier = null;
myType = type;
}
public MavenDependencyCompletionItem(@Nullable String coord) {
this(coord, null);
}
@Nullable
public Type getType() {
return myType;
}
public String getPackaging() {
return packaging;
}
public String getClassifier() {
return classifier;
}
}
@@ -0,0 +1,32 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion.model;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
public class MavenDependencyCompletionItemWithClass extends MavenDependencyCompletionItem {
private final Collection<String> myNames;
public MavenDependencyCompletionItemWithClass(@Nullable String groupId,
@Nullable String artifactId,
@Nullable String version,
@Nullable Type type,
Collection<String> klassNames) {
super(groupId, artifactId, version, type);
myNames = klassNames;
}
public MavenDependencyCompletionItemWithClass(@Nullable String coord,
@Nullable Type type,
Collection<String> klassNames) {
super(coord, type);
myNames = klassNames;
}
public Collection<String> getNames() {
return Collections.unmodifiableCollection(myNames);
}
}
@@ -0,0 +1,40 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion.model;
import java.util.EnumSet;
public class SearchParameters {
public enum Flags {
ALL_VERSIONS("requesting all versions"),
FULL_RESOLVE("should not return partially resolved artifacts"),
NOT_DEDUPLICATE("Deduplication will not be called");
Flags(String desc) {}
}
public static final SearchParameters DEFAULT = new SearchParameters(20, 500, EnumSet.noneOf(Flags.class));
private final int maxResults;
private final long millisToWait;
private final EnumSet<Flags> myFlags;
public SearchParameters(int maxResults, long wait, EnumSet<Flags> flags) {
this.maxResults = maxResults;
millisToWait = wait;
myFlags = flags;
}
public int getMaxResults() {
return maxResults;
}
public long getMillisToWait() {
return millisToWait;
}
public EnumSet<Flags> getFlags() {
return EnumSet.copyOf(myFlags);
}
}
@@ -4,6 +4,7 @@ maven.index.type=Type
maven.index.updated=Updated
maven.index.updated.never=Never
maven.index.updated.error=Error
maven.index.updated.notapplicable=N/A
maven.indices.updating=Updating Maven Repository Indices...
maven.indices.updating.index=Updating [{0}] {1}
repository.plugin.corrupt={0} not a Maven 2 plugin file
@@ -151,6 +151,9 @@
<completion.contributor language="XML"
implementationClass="org.jetbrains.idea.maven.dom.model.completion.MavenDependenciesCompletionProvider"/>
<completion.contributor language="XML"
implementationClass="org.jetbrains.idea.maven.dom.model.completion.MavenArtifactCompletionContributor"/>
<psi.referenceContributor implementation="org.jetbrains.idea.maven.dom.references.MavenPropertyPsiReferenceContributor"/>
<psi.referenceContributor language="XML" implementation="org.jetbrains.idea.maven.plugins.api.MavenPluginParamReferenceContributor"/>
@@ -18,7 +18,6 @@ package org.jetbrains.idea.maven.dom;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiReference;
import org.jetbrains.idea.maven.indices.MavenIndex;
import org.jetbrains.idea.maven.indices.MavenIndicesTestFixture;
import org.jetbrains.idea.maven.indices.MavenProjectIndicesManager;
@@ -81,13 +80,6 @@ public class MavenExtensionCompletionAndResolutionTest extends MavenDomWithIndic
MavenProjectIndicesManager instance = MavenProjectIndicesManager.getInstance(myProject);
System.out.println("GetArtifacts: " + new HashSet<>(instance.getArtifactIds("org.apache.maven.plugins")));
System.out.println("Indexes: " + instance.getIndices());
for (MavenIndex index : instance.getIndices()) {
System.out.println("Index: repositoryId=" + index.getRepositoryId() + " repositoryUrl=" + index.getRepositoryUrl() + " repositoryPathOrUrl" + index.getRepositoryPathOrUrl());
System.out.println("Dir: " + index.getDir());
index.printInfo();
}
throw new AssertionError("GetArtifacts: " + instance.getArtifactIds("org.apache.maven.plugins") + " Indexes: " + instance.getIndices());
}
}
@@ -49,40 +49,19 @@ public class MavenIndicesManagerTest extends MavenIndicesTestCase {
}
}
public void testEnsuringLocalRepositoryIndex() {
File dir1 = myIndicesFixture.getRepositoryHelper().getTestData("dir/foo");
File dir2 = myIndicesFixture.getRepositoryHelper().getTestData("dir\\foo");
File dir3 = myIndicesFixture.getRepositoryHelper().getTestData("dir\\foo\\");
File dir4 = myIndicesFixture.getRepositoryHelper().getTestData("dir/bar");
List<MavenIndex> indices1 = myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, dir1,
Collections.emptyList());
assertEquals(1, indices1.size());
assertTrue(myIndicesFixture.getIndicesManager().getIndices().contains(indices1.get(0)));
assertEquals(indices1, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, dir2,
Collections.emptyList()));
assertEquals(indices1, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, dir3,
Collections.emptyList()));
List<MavenIndex> indices2 = myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, dir4,
Collections.emptyList());
assertFalse(indices1.get(0).equals(indices2.get(0)));
}
public void testEnsuringRemoteRepositoryIndex() {
File local = myIndicesFixture.getRepositoryHelper().getTestData("dir");
Pair<String, String> remote1 = Pair.create("id1", "http://foo/bar");
Pair<String, String> remote2 = Pair.create("id1", " http://foo\\bar\\\\ ");
Pair<String, String> remote3 = Pair.create("id3", "http://foo\\bar\\baz");
Pair<String, String> remote4 = Pair.create("id4", "http://foo/bar"); // same url
Pair<String, String> remote5 = Pair.create("id4", "http://foo/baz"); // same id
assertEquals(2, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, local, Collections.singleton(remote1)).size());
assertEquals(2, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, local, asList(remote1, remote2)).size());
assertEquals(3, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, local, asList(remote1, remote2, remote3)).size());
assertEquals(3, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, local, asList(remote1, remote2, remote3, remote4)).size());
assertEquals(4, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, local, asList(remote1, remote2, remote3, remote4, remote5)).size());
assertEquals(2, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, Collections.singleton(remote1)).size());
assertEquals(2, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, asList(remote1, remote2)).size());
assertEquals(3, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, asList(remote1, remote2, remote3)).size());
assertEquals(3, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, asList(remote1, remote2, remote3, remote4)).size());
assertEquals(4, myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, asList(remote1, remote2, remote3, remote4, remote5)).size());
}
public void testDefaultArchetypes() {
@@ -91,7 +70,7 @@ public class MavenIndicesManagerTest extends MavenIndicesTestCase {
public void testIndexedArchetypes() throws Exception {
myIndicesFixture.getRepositoryHelper().addTestData("archetypes");
myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, myIndicesFixture.getRepositoryHelper().getTestData("archetypes"),
myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject,
Collections.emptyList());
assertArchetypeExists("org.apache.maven.archetypes:maven-archetype-foobar:1.0");
@@ -99,7 +78,7 @@ public class MavenIndicesManagerTest extends MavenIndicesTestCase {
public void testIndexedArchetypesWithSeveralIndicesAfterReopening() throws Exception {
myIndicesFixture.getRepositoryHelper().addTestData("archetypes");
myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject, myIndicesFixture.getRepositoryHelper().getTestData("archetypes"),
myIndicesFixture.getIndicesManager().ensureIndicesExist(myProject,
Collections.singleton(Pair.create("id", "foo://bar.baz")));
assertArchetypeExists("org.apache.maven.archetypes:maven-archetype-foobar:1.0");
@@ -1,487 +0,0 @@
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.idea.maven.indices;
import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.util.io.FileUtil;
import org.apache.lucene.index.Term;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.WildcardQuery;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.idea.maven.MavenCustomRepositoryHelper;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.server.MavenIndexerWrapper;
import org.jetbrains.idea.maven.server.MavenServerIndexer;
import org.jetbrains.idea.maven.server.MavenServerManager;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class MavenIndicesTest extends MavenIndicesTestCase {
private MavenCustomRepositoryHelper myRepositoryHelper;
private MavenIndices myIndices;
private MavenIndexerWrapper myIndexer;
private File myIndicesDir;
private boolean isBroken;
@Override
public void setUp() throws Exception {
super.setUp();
updateSettingsXmlFully("<settings>" +
" <mirrors>" +
" </mirrors>" +
"</settings>");
myRepositoryHelper = new MavenCustomRepositoryHelper(myDir, "local1", "local2", "remote");
initIndices();
}
@Override
protected void tearDown() throws Exception {
try {
shutdownIndices();
}
catch (Throwable e) {
addSuppressedException(e);
}
finally {
super.tearDown();
}
}
private void initIndices() {
initIndices("indices");
}
private void initIndices(String relativeDir) {
if (myIndices != null) {
try {
shutdownIndices();
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
myIndexer = MavenServerManager.getInstance().createIndexer();
myIndicesDir = new File(myDir, relativeDir);
myIndices = new MavenIndices(myIndexer, myIndicesDir, new MavenIndex.IndexListener() {
@Override
public void indexIsBroken(@NotNull MavenIndex index) {
isBroken = true;
}
});
}
private void shutdownIndices() {
myIndices.close();
myIndexer.releaseInTests();
}
private static void assertSearchResults(MavenIndex i, Query query, String... expectedArtifacts) {
List<String> actualArtifacts = new ArrayList<>();
for (MavenArtifactInfo each : i.search(query, 100)) {
actualArtifacts.add(each.getGroupId() + ":" + each.getArtifactId() + ":" + each.getVersion());
}
assertUnorderedElementsAreEqual(actualArtifacts, expectedArtifacts);
}
public void testCreatingAndUpdatingLocalWhenNoDirectory() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("do_not_exist"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds());
}
public void testCreatingSeveral() throws Exception {
MavenIndex i1 = myIndices.add("id1", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndex i2 = myIndices.add("id2", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i1, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
MavenIndices.updateOrRepair(i2, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i1.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
assertUnorderedElementsAreEqual(i2.getGroupIds(), "jmock");
}
public void testCreatingSeveralWithSameIdAndDifferentUrl() throws Exception {
MavenIndex i1 = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndex i2 = myIndices.add("id", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
assertNotSame(i1, i2);
MavenIndices.updateOrRepair(i1, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
MavenIndices.updateOrRepair(i2, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i1.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
assertUnorderedElementsAreEqual(i2.getGroupIds(), "jmock");
}
public void testCreatingSeveralWithDifferentIdAndSameUrl() throws Exception {
MavenIndex i1 = myIndices.add("id1", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndex i2 = myIndices.add("id2", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
assertSame(i1, i2);
MavenIndices.updateOrRepair(i1, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
MavenIndices.updateOrRepair(i2, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i1.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
assertUnorderedElementsAreEqual(i2.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
}
public void testAddingWithoutUpdate() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
assertTrue(i.getGroupIds().isEmpty());
}
public void testUpdatingLocalClearsPreviousIndex() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
myRepositoryHelper.delete("local1");
myRepositoryHelper.copy("local2", "local1");
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds(), "jmock");
}
public void testClearingUpdateDirAfterUpdate() {
ignore();
//MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
//
//myIndices.updateOrRepair(i, myEmbedder, true, new EmptyProgressIndicator());
//assertUnorderedElementsAreEqual(i.getGroupIds(), "junit");
//
//assertFalse(i.getUpdateDir().exists());
}
public void testAddingRemote() throws Exception {
MavenIndex i = myIndices.add("id", "file:///" + myRepositoryHelper.getTestDataPath("remote"), MavenIndex.Kind.REMOTE);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds(), "junit");
}
public void testUpdatingRemote() throws Exception {
MavenIndex i = myIndices.add("id", "file:///" + myRepositoryHelper.getTestDataPath("remote"), MavenIndex.Kind.REMOTE);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
//shouldn't throw 'The existing index is for repository [remote] and not for repository [xxx]'
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds(), "junit");
}
public void testDoNotAddSameIndexTwice() throws Exception {
MavenIndex local = myIndices.add("local", myRepositoryHelper.getTestDataPath("foo"), MavenIndex.Kind.LOCAL);
if (!SystemInfo.isFileSystemCaseSensitive) {
assertSame(local, myIndices.add("local", myRepositoryHelper.getTestDataPath("FOO"), MavenIndex.Kind.LOCAL));
}
assertSame(local, myIndices.add("local", myRepositoryHelper.getTestDataPath("foo") + "/\\", MavenIndex.Kind.LOCAL));
assertSame(local, myIndices.add("local", " " + myRepositoryHelper.getTestDataPath("foo") + " ", MavenIndex.Kind.LOCAL));
MavenIndex remote = myIndices.add("remote", "http://foo.bar", MavenIndex.Kind.REMOTE);
assertSame(remote, myIndices.add("remote", "HTTP://FOO.BAR", MavenIndex.Kind.REMOTE));
assertSame(remote, myIndices.add("remote", "http://foo.bar/\\", MavenIndex.Kind.REMOTE));
assertSame(remote, myIndices.add("remote", " http://foo.bar ", MavenIndex.Kind.REMOTE));
}
public void testAddingInAbsenceOfParentDirectories() throws Exception {
String subDir = "subDir1/subDir2/index";
initIndices(subDir);
myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
}
public void testAddingCorrectlyToIndexer() throws Exception {
assertEquals(0, myIndexer.getIndexCount());
MavenIndex i1 = myIndices.add("local", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
assertEquals(1, myIndexer.getIndexCount());
MavenIndex i2 = myIndices.add("local", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
assertEquals(2, myIndexer.getIndexCount());
MavenIndices.updateOrRepair(i1, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertEquals(2, myIndexer.getIndexCount());
MavenIndices.updateOrRepair(i2, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertEquals(2, myIndexer.getIndexCount());
}
public void testClearingIndexDirOnLoadError() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
shutdownIndices();
FileWriter w = new FileWriter(new File(i.getDir(), MavenIndex.INDEX_INFO_FILE));
w.write("bad content");
w.close();
initIndices();
assertTrue(myIndices.getIndices().isEmpty());
assertFalse(i.getDir().exists());
}
public void testDoNotClearAlreadyLoadedIndexesOnLoadError() throws Exception {
myIndices.add("id1", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndex i2 = myIndices.add("id2", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
shutdownIndices();
FileWriter w = new FileWriter(new File(i2.getDir(), MavenIndex.INDEX_INFO_FILE));
w.write("bad content");
w.close();
initIndices();
assertEquals(1, myIndices.getIndices().size());
assertEquals("local1", myIndices.getIndices().get(0).getRepositoryFile().getName());
}
public void testLoadingIndexIfCachesAreBroken() throws Exception {
MavenIndex i1 = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndex i2 = myIndices.add("id", myRepositoryHelper.getTestDataPath("local2"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i1, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
MavenIndices.updateOrRepair(i2, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i1.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
assertUnorderedElementsAreEqual(i2.getGroupIds(), "jmock");
shutdownIndices();
damageFile(i1, "artifactIds-map.dat", true);
initIndices();
assertEquals(2, myIndices.getIndices().size());
assertTrue(myIndices.getIndices().get(0).getGroupIds().isEmpty());
assertUnorderedElementsAreEqual(myIndices.getIndices().get(1).getGroupIds(), "jmock");
MavenIndices.updateOrRepair(myIndices.getIndices().get(0), false, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(myIndices.getIndices().get(0).getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
}
public void testDoNotLoadSameIndexTwice() throws Exception {
MavenIndex index = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
File dir = index.getDir();
shutdownIndices();
File copy = new File(dir.getParentFile(), "ZZZ_INDEX_COPY");
FileUtil.copyDir(dir, copy);
initIndices();
assertEquals(1, myIndices.getIndices().size());
assertFalse(copy.exists());
}
public void testAddingIndexWithExistingDirectoryDoesNotThrowException() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
shutdownIndices();
initIndices();
i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
}
public void testIndicesAreValidAfterReopening() throws Exception {
myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
shutdownIndices();
initIndices();
assertFalse(isBroken);
}
public void testSavingFailureMessage() throws Exception {
MavenIndex i = myIndices.add("id", "xxx", MavenIndex.Kind.REMOTE);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
String message = i.getFailureMessage();
assertNotNull(message);
shutdownIndices();
initIndices();
assertEquals(message, myIndices.getIndices().get(0).getFailureMessage());
}
public void testRepairingIndicesOnReadError() throws Exception {
MavenIndex index = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(index, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
shutdownIndices();
damageFile(index, "artifactIds-map.dat", false);
initIndices();
index = myIndices.getIndices().get(0);
index.getGroupIds();
assertTrue(isBroken);
assertTrue(index.getGroupIds().isEmpty());
MavenIndices.updateOrRepair(myIndices.getIndices().get(0), false, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(index.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
}
public void testRepairingIndicesOnReadWhileAddingArtifact() throws Exception {
MavenIndex index = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(index, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
shutdownIndices();
damageFile(index, "artifactIds-map.dat", false);
initIndices();
index = myIndices.getIndices().get(0);
index.addArtifact(null);
assertTrue(isBroken);
assertTrue(index.getGroupIds().isEmpty());
MavenIndices.updateOrRepair(myIndices.getIndices().get(0), false, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(index.getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
}
public void testCorrectlyClosingIndicesOnRemoteFacadeShutdown() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
MavenServerManager.getInstance().shutdown(true);
initIndices();
i = myIndices.getIndices().get(0);
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*junit*")),
"junit:junit:3.8.1", "junit:junit:3.8.2", "junit:junit:4.0");
}
public void testRestartingIndicesManagerOnRemoteMavenServerShutdown() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*junit*")),
"junit:junit:3.8.1", "junit:junit:3.8.2", "junit:junit:4.0");
MavenServerManager.getInstance().shutdown(true);
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*junit*")),
"junit:junit:3.8.1", "junit:junit:3.8.2", "junit:junit:4.0");
}
private static void damageFile(MavenIndex index, String fileName, boolean fullDamage) throws IOException {
File cachesDir = index.getCurrentDataDir();
File file = new File(cachesDir, fileName);
assertTrue(file.exists());
if (fullDamage) {
FileWriter w = new FileWriter(file);
w.write("bad content");
w.close();
}
else {
byte[] content = FileUtil.loadFileBytes(file);
for (int i = 0; i < content.length; i+=2) {
content[i] = -1;
}
FileUtil.writeToFile(file, content);
}
}
public void testGettingArtifactInfos() throws Exception {
myRepositoryHelper.copy("local2", "local1");
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertUnorderedElementsAreEqual(i.getGroupIds(), "junit", "jmock", "asm", "commons-io", "org.ow2.asm");
assertUnorderedElementsAreEqual(i.getArtifactIds("junit"), "junit");
assertUnorderedElementsAreEqual(i.getArtifactIds("jmock"), "jmock");
assertUnorderedElementsAreEqual(i.getArtifactIds("unknown"));
assertUnorderedElementsAreEqual(i.getVersions("junit", "junit"), "3.8.1", "3.8.2", "4.0");
assertUnorderedElementsAreEqual(i.getVersions("junit", "jmock"));
assertUnorderedElementsAreEqual(i.getVersions("unknown", "unknown"));
}
public void testGettingArtifactInfosFromNotUpdatedRepositories() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
assertUnorderedElementsAreEqual(i.getGroupIds()); // shouldn't throw
}
public void testGettingArtifactInfosAfterReload() throws Exception {
MavenIndices.updateOrRepair(myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL),
true,
getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
shutdownIndices();
initIndices();
assertUnorderedElementsAreEqual(myIndices.getIndices().get(0).getGroupIds(), "junit", "asm", "commons-io", "org.ow2.asm");
}
public void testHasArtifactInfo() throws Exception {
myRepositoryHelper.copy("local2", "local1");
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertTrue(i.hasGroupId("junit"));
assertTrue(i.hasGroupId("jmock"));
assertFalse(i.hasGroupId("xxx"));
assertTrue(i.hasArtifactId("junit", "junit"));
assertTrue(i.hasArtifactId("jmock", "jmock"));
assertFalse(i.hasArtifactId("junit", "jmock"));
assertTrue(i.hasVersion("junit", "junit", "4.0"));
assertTrue(i.hasVersion("jmock", "jmock", "1.0.0"));
assertFalse(i.hasVersion("junit", "junit", "666"));
}
public void testSearching() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*junit*")),
"junit:junit:3.8.1", "junit:junit:3.8.2", "junit:junit:4.0");
}
public void testSearchingAfterArtifactAddition() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
i.addArtifact(new File(myRepositoryHelper.getTestDataPath("local2/jmock/jmock/1.0.0/jmock-1.0.0.jar")));
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*mock*")), "jmock:jmock:1.0.0");
}
public void testSearchingForClasses() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*runwith*")), "junit:junit:4.0");
}
public void testSearchingForClassesAfterArtifactAddition() throws Exception {
MavenIndex i = myIndices.add("id", myRepositoryHelper.getTestDataPath("local1"), MavenIndex.Kind.LOCAL);
MavenIndices.updateOrRepair(i, true, getMavenGeneralSettings(), EMPTY_MAVEN_PROCESS);
i.addArtifact(new File(myRepositoryHelper.getTestDataPath("local2/jmock/jmock/1.0.0/jmock-1.0.0.jar")));
assertSearchResults(i, new WildcardQuery(new Term(MavenServerIndexer.SEARCH_TERM_CLASS_NAMES, "*mock*")), "jmock:jmock:1.0.0");
}
}
@@ -15,6 +15,10 @@
*/
package org.jetbrains.idea.maven.indices;
import org.jetbrains.idea.maven.onlinecompletion.DependencySearchService;
import org.jetbrains.idea.maven.onlinecompletion.LocalCompletionSearch;
import org.jetbrains.idea.maven.onlinecompletion.central.MavenCentralOnlineSearch;
import java.util.List;
public class MavenProjectIndicesManagerTest extends MavenIndicesTestCase {
@@ -45,139 +49,21 @@ public class MavenProjectIndicesManagerTest extends MavenIndicesTestCase {
assertEquals(1, indices.size());
assertEquals(MavenIndex.Kind.LOCAL, indices.get(0).getKind());
assertEquals(MavenSearchIndex.Kind.LOCAL, indices.get(0).getKind());
assertTrue(indices.get(0).getRepositoryPathOrUrl().endsWith("local1"));
assertTrue(myIndicesFixture.getProjectIndicesManager().hasVersion("junit", "junit", "4.0"));
}
public void testAutomaticallyAddRemoteRepositoriesOnProjectUpdate() {
public void testAutomaticallyAddSearchService() {
importProject("<groupId>test</groupId>" +
"<artifactId>project</artifactId>" +
"<version>1</version>");
List<MavenIndex> indices = myIndicesFixture.getProjectIndicesManager().getIndices();
assertEquals(2, indices.size());
DependencySearchService service = myIndicesFixture.getProjectIndicesManager().getSearchService();
assertEquals(2, service.getProviders().size());
assertTrue(indices.get(0).getRepositoryPathOrUrl().endsWith("local1"));
assertEquals("https://repo.maven.apache.org/maven2", indices.get(1).getRepositoryPathOrUrl());
assertTrue(service.getProviders().get(0) instanceof LocalCompletionSearch);
assertTrue(service.getProviders().get(1) instanceof MavenCentralOnlineSearch);
}
public void testUpdatingIndicesOnResolution() {
removeFromLocalRepository("junit/junit/4.0");
myIndicesFixture.getProjectIndicesManager().scheduleUpdate(myIndicesFixture.getProjectIndicesManager().getIndices());
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getVersions("junit", "junit"), "3.8.1", "3.8.2");
importProject("<groupId>test</groupId>" +
"<artifactId>project</artifactId>" +
"<version>1</version>" +
"<dependencies>" +
" <dependency>" +
" <groupId>junit</groupId>" +
" <artifactId>junit</artifactId>" +
" <version>4.0</version>" +
" </dependency>" +
"</dependencies>");
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getVersions("junit", "junit"), "3.8.1", "3.8.2", "4.0");
}
public void testUpdatingIndexUsingMirrors() throws Exception {
myIndicesFixture.tearDown();
myIndicesFixture = new MavenIndicesTestFixture(myDir.toPath(), myProject, "local2", "remote_mirror");
myIndicesFixture.setUp();
updateSettingsXmlFully("<settings>" +
" <mirrors>" +
" </mirrors>" +
"</settings>");
importProject("<groupId>test</groupId>" +
"<artifactId>project</artifactId>" +
"<version>1</version>" +
"<repositories>" +
" <repository>" +
" <id>central</id>" +
" <url>xxx://does.not.matter</url>" +
" </repository>" +
"</repositories>");
myIndicesFixture.getProjectIndicesManager().scheduleUpdateAll();
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getGroupIds(), "test", "jmock");
updateSettingsXmlFully("<settings>" +
" <mirrors>" +
" <mirror>" +
" <id>nexus</id>" +
" <mirrorOf>anotherRepoId</mirrorOf>" +
" <url>file:///" + myIndicesFixture.getRepositoryHelper().getTestDataPath("remote_mirror") + "</url>" +
" </mirror>" +
" </mirrors>" +
"</settings>");
myIndicesFixture.getProjectIndicesManager().scheduleUpdateAll();
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getGroupIds(), "test", "jmock");
updateSettingsXmlFully("<settings>" +
" <mirrors>" +
" <mirror>" +
" <id>nexus</id>" +
" <mirrorOf>central</mirrorOf>" +
" <url>file:///" + myIndicesFixture.getRepositoryHelper().getTestDataPath("remote_mirror") + "</url>" +
" </mirror>" +
" </mirrors>" +
"</settings>");
myIndicesFixture.getProjectIndicesManager().scheduleUpdateAll();
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getGroupIds(), "test", "jmock", "junit");
myIndicesFixture.tearDown();
myIndicesFixture = new MavenIndicesTestFixture(myDir.toPath(), myProject, "local2", "remote_mirror");
myIndicesFixture.setUp();
updateSettingsXmlFully("<settings>" +
" <mirrors>" +
" <mirror>" +
" <id>nexus</id>" +
" <mirrorOf>*</mirrorOf>" +
" <url>file:///" + myIndicesFixture.getRepositoryHelper().getTestDataPath("remote_mirror") + "</url>" +
" </mirror>" +
" </mirrors>" +
"</settings>");
myIndicesFixture.getProjectIndicesManager().scheduleUpdateAll();
assertUnorderedElementsAreEqual(myIndicesFixture.getProjectIndicesManager().getGroupIds(), "test", "jmock", "junit");
}
public void testCheckingLocalRepositoryForAbsentIndices() throws Exception {
myIndicesFixture.tearDown();
myIndicesFixture = new MavenIndicesTestFixture(myDir.toPath(), myProject, "local2");
myIndicesFixture.setUp();
myIndicesFixture.addToRepository("local1");
assertUnorderedElementsAreEqual(
myIndicesFixture.getProjectIndicesManager().getGroupIds(), "jmock");
assertTrue(myIndicesFixture.getProjectIndicesManager().hasGroupId("junit"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasGroupId("xxx"));
assertTrue(myIndicesFixture.getProjectIndicesManager().hasArtifactId("junit", "junit"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasArtifactId("junit", "xxx"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasArtifactId("xxx", "junit"));
assertTrue(myIndicesFixture.getProjectIndicesManager().hasVersion("junit", "junit", "4.0"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasVersion("junit", "junit", "xxx"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasVersion("junit", "xxx", "4.0"));
assertFalse(myIndicesFixture.getProjectIndicesManager().hasVersion("xxx", "junit", "4.0"));
//assertUnorderedElementsAreEqual(
// myIndicesFixture.getProjectIndicesManager().getGroupIds(), "junit", "jmock");
//assertUnorderedElementsAreEqual(
// myIndicesFixture.getProjectIndicesManager().getArtifactIds("junit"), "junit");
//assertUnorderedElementsAreEqual(
// myIndicesFixture.getProjectIndicesManager().getVersions("junit", "junit"), "4.0");
}
}
@@ -15,11 +15,14 @@
*/
package org.jetbrains.idea.maven.indices;
import org.jetbrains.idea.maven.model.MavenArtifactInfo;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.junit.Ignore;
import java.util.ArrayList;
import java.util.List;
@Ignore("tests for online search to be ready")
public class MavenSearcherTest extends MavenIndicesTestCase {
MavenIndicesTestFixture myIndicesFixture;
@@ -44,7 +47,8 @@ public class MavenSearcherTest extends MavenIndicesTestCase {
}
public void testClassSearch() {
assertTrue(!getClassSearchResults("").isEmpty());
if(ignore()) return;
assertTrue(getClassSearchResults("").isEmpty());
assertClassSearchResults("TestCas",
"TestCase(junit.framework) junit:junit:4.0 junit:junit:3.8.2 junit:junit:3.8.1",
@@ -95,6 +99,7 @@ public class MavenSearcherTest extends MavenIndicesTestCase {
}
public void testArtifactSearch() {
if(ignore()) return;
assertArtifactSearchResults("",
"asm:asm:3.3.1 asm:asm:3.3",
"asm:asm-attrs:2.2.1",
@@ -124,8 +129,8 @@ public class MavenSearcherTest extends MavenIndicesTestCase {
private List<String> getClassSearchResults(String pattern) {
List<String> actualArtifacts = new ArrayList<>();
for (MavenClassSearchResult eachResult : new MavenClassSearcher().search(myProject, pattern, 100)) {
StringBuilder s = new StringBuilder(eachResult.className + "(" + eachResult.packageName + ")");
for (MavenArtifactInfo eachVersion : eachResult.versions) {
StringBuilder s = new StringBuilder(eachResult.getClassName() + "(" + eachResult.getPackageName() + ")");
for (MavenDependencyCompletionItem eachVersion : eachResult.getSearchResults()) {
if (s.length() > 0) s.append(" ");
s.append(eachVersion.getGroupId()).append(":").append(eachVersion.getArtifactId()).append(":").append(eachVersion.getVersion());
}
@@ -138,7 +143,7 @@ public class MavenSearcherTest extends MavenIndicesTestCase {
List<String> actual = new ArrayList<>();
for (MavenArtifactSearchResult eachResult : new MavenArtifactSearcher().search(myProject, pattern, 100)) {
StringBuilder s = new StringBuilder();
for (MavenArtifactInfo eachVersion : eachResult.versions) {
for (MavenDependencyCompletionItem eachVersion : eachResult.getSearchResults()) {
if (s.length() > 0) s.append(" ");
s.append(eachVersion.getGroupId()).append(":").append(eachVersion.getArtifactId()).append(":").append(eachVersion.getVersion());
}
@@ -0,0 +1,66 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import com.intellij.testFramework.UsefulTestCase;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import static java.util.Arrays.asList;
public class DeduplicationCollectorTest extends UsefulTestCase {
public void testLocalBeforeRemote() {
MavenDependencyCompletionItem local = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.LOCAL);
MavenDependencyCompletionItem remote = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.REMOTE);
Stream<List<MavenDependencyCompletionItem>> stream = Arrays.stream(new List[]{
asList(local),
asList(remote)}
);
List<MavenDependencyCompletionItem> result = stream.collect(new DeduplicationCollector<>(m -> m.getDisplayString()));
assertSize(1, result);
assertEquals(MavenDependencyCompletionItem.Type.LOCAL, result.get(0).getType());
}
public void testRemoteBeforeLocal() {
MavenDependencyCompletionItem local = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.LOCAL);
MavenDependencyCompletionItem remote = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.REMOTE);
Stream<List<MavenDependencyCompletionItem>> stream = Arrays.stream(new List[]{
asList(remote),
asList(local)}
);
List<MavenDependencyCompletionItem> result = stream.collect(new DeduplicationCollector<>(m -> m.getDisplayString()));
assertSize(1, result);
assertEquals(MavenDependencyCompletionItem.Type.LOCAL, result.get(0).getType());
}
public void testShowLocalVersions() {
MavenDependencyCompletionItem local = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.LOCAL);
MavenDependencyCompletionItem remote = new MavenDependencyCompletionItem("group:artifact:2", MavenDependencyCompletionItem.Type.REMOTE);
Stream<List<MavenDependencyCompletionItem>> stream = Arrays.stream(new List[]{
asList(remote),
asList(local)}
);
List<MavenDependencyCompletionItem> result =
stream.collect(new DeduplicationCollector<>(m -> m.getGroupId() + ":" + m.getArtifactId()));
assertSize(1, result);
assertEquals(MavenDependencyCompletionItem.Type.LOCAL, result.get(0).getType());
}
public void testShowBothVersions() {
MavenDependencyCompletionItem local = new MavenDependencyCompletionItem("group:artifact:1", MavenDependencyCompletionItem.Type.LOCAL);
MavenDependencyCompletionItem remote = new MavenDependencyCompletionItem("group:artifact:2", MavenDependencyCompletionItem.Type.REMOTE);
Stream<List<MavenDependencyCompletionItem>> stream = Arrays.stream(new List[]{
asList(remote),
asList(local)}
);
List<MavenDependencyCompletionItem> result = stream.collect(new DeduplicationCollector<>(m -> m.getDisplayString()));
assertSize(2, result);
}
}
@@ -0,0 +1,70 @@
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.idea.maven.onlinecompletion;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.idea.maven.MavenTestCase;
import org.jetbrains.idea.maven.onlinecompletion.model.MavenDependencyCompletionItem;
import org.jetbrains.idea.maven.onlinecompletion.model.SearchParameters;
import org.junit.Before;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import java.util.List;
public class LocalCompletionSearchTest extends MavenTestCase {
private File myLocalRepo;
@Before
@Override
public void setUp() throws Exception {
super.setUp();
myLocalRepo = new File(myDir, ".m2/repository");
createFile("org/apache/commons/commons-collections4/4.3/commons-collections4-4.3.pom");
createFile("org/apache/commons/commons-collections4/4.2/commons-collections4-4.2.pom");
createFile("org/apache/commons/commons-lang3/3.1/commons-lang3-3.1.pom");
createFile("xalan/xalan/2.6.0/xalan-2.6.0.pom");
createFile("xalan/serializer/2.7.2/serializer-2.7.2.pom");
FileUtil.ensureExists(myLocalRepo);
}
@Test
public void testFindAllGroups() throws IOException {
LocalCompletionSearch search = new LocalCompletionSearch(myLocalRepo);
List<MavenDependencyCompletionItem> items = search.findGroupCandidates(null, SearchParameters.DEFAULT);
List<String> map = ContainerUtil.map(items, i -> i.getGroupId());
assertUnorderedElementsAreEqual(map, "org.apache.commons",
"xalan");
}
@Test
public void testArtifacts() throws IOException {
LocalCompletionSearch search = new LocalCompletionSearch(myLocalRepo);
List<MavenDependencyCompletionItem> items =
search.findArtifactCandidates(new MavenDependencyCompletionItem("org.apache.commons"), SearchParameters.DEFAULT);
List<String> map = ContainerUtil.map(items, i -> i.getArtifactId());
assertUnorderedElementsAreEqual(map, "commons-collections4",
"commons-lang3");
}
@Test
public void testVersions() throws IOException {
LocalCompletionSearch search = new LocalCompletionSearch(myLocalRepo);
List<MavenDependencyCompletionItem> items =
search.findAllVersions(
new MavenDependencyCompletionItem("org.apache.commons:commons-collections4"), SearchParameters.DEFAULT);
List<String> map = ContainerUtil.map(items, i -> i.getVersion());
assertUnorderedElementsAreEqual(map, "4.3",
"4.2");
}
private void createFile(String path) throws IOException {
File file = new File(myLocalRepo, path);
FileUtil.ensureCanCreateFile(file);
file.createNewFile();
}
}