Skip to content

Commit

Permalink
Allow * expression for quarkus:add-extension
Browse files Browse the repository at this point in the history
  • Loading branch information
Dufgui committed Aug 23, 2019
1 parent f9ea1a8 commit a45828e
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,13 @@
import static io.quarkus.maven.utilities.MojoUtils.readPom;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
import java.util.stream.Collectors;

import org.apache.maven.model.Dependency;
Expand Down Expand Up @@ -74,16 +77,89 @@ static SelectionResult select(String query, List<Extension> extensions, boolean
matchesLabels = extensions.stream()
.filter(extension -> extension.labels().contains(q)).collect(Collectors.toList());
} else {
matchesLabels = new ArrayList<>();
matchesLabels = Collections.emptyList();
}

// find by pattern
Set<Extension> matchesPatterns;
Pattern pattern = toRegex(q);
if(pattern != null) {
matchesPatterns = extensions.stream().filter(extension -> pattern.matcher(extension.getName().toLowerCase()).matches()
|| pattern.matcher(extension.getArtifactId().toLowerCase()).matches()
|| pattern.matcher(extension.getShortName().toLowerCase()).matches()
|| matchLabels(pattern, extension.getLabels())).collect(Collectors.toSet());
return new SelectionResult(matchesPatterns, true);
} else {
matchesPatterns = Collections.emptySet();
}

Set<Extension> candidates = new LinkedHashSet<>();
candidates.addAll(matchesNameOrArtifactId);
candidates.addAll(matchesShortName);
candidates.addAll(partialMatches);
candidates.addAll(matchesLabels);
candidates.addAll(matchesPatterns);
return new SelectionResult(candidates, false);
}

private static boolean matchLabels(Pattern pattern, String[] labels) {
boolean matches = false;
// if any label match it's ok
for (int i = 0; i < labels.length; i++) {
matches = matches | pattern.matcher(labels[i].toLowerCase()).matches();
}
return matches;
}

private static Pattern toRegex(final String str) {
try {
String wildcardToRegex = wildcardToRegex(str);
if(wildcardToRegex != null && !wildcardToRegex.isEmpty()) {
return Pattern.compile(wildcardToRegex);
}
} catch (PatternSyntaxException e) {
//ignore it
}
return null;
}

public static String wildcardToRegex(String wildcard) {
if(wildcard == null || wildcard.isEmpty()) {
return null;
}
// don't try with file match char in pattern
if(!(wildcard.contains("*") || wildcard.contains("?"))) {
return null;
}
StringBuffer s = new StringBuffer(wildcard.length());
s.append("^.*");
for (int i = 0, is = wildcard.length(); i < is; i++) {
char c = wildcard.charAt(i);
switch(c) {
case '*':
s.append(".*");
break;
case '?':
s.append(".");
break;
case '^': // escape character in cmd.exe
s.append("\\");
break;
// escape special regexp-characters
case '(': case ')': case '[': case ']': case '$':
case '.': case '{': case '}': case '|':
case '\\':
s.append("\\");
s.append(c);
break;
default:
s.append(c);
break;
}
}
s.append(".*$");
return(s.toString());
}

private static boolean matchesShortName(Extension extension, String q) {
return q.equalsIgnoreCase(extension.getShortName());
Expand Down Expand Up @@ -131,9 +207,10 @@ public AddExtensionResult addExtensions(final Set<String> extensions) throws IOE
success = false;
}
} else { // Matches.
final Extension extension = result.getMatch();
// Don't set success to false even if the dependency is not added; as it's should be idempotent.
updated = buildFile.addDependency(dependenciesFromBom, extension) || updated;
for (Extension extension : result) {
// Don't set success to false even if the dependency is not added; as it's should be idempotent.
updated = buildFile.addDependency(dependenciesFromBom, extension) || updated;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package io.quarkus.cli.commands;

import java.util.Collections;
import java.util.Iterator;
import java.util.Set;

import io.quarkus.dependencies.Extension;

public class SelectionResult {
public class SelectionResult implements Iterable<Extension>{

private final Set<Extension> extensions;
private final boolean matches;
Expand All @@ -22,13 +24,11 @@ public boolean matches() {
return matches;
}

public Extension getMatch() {
@Override
public Iterator<Extension> iterator() {
if (matches) {
if (extensions.isEmpty() || extensions.size() > 1) {
throw new IllegalStateException("Invalid selection result");
}
return extensions.iterator().next();
return extensions.iterator();
}
return null;
return Collections.emptyIterator();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,38 @@ void testPartialMatches() throws IOException {
hasDependency(model, "quarkus-hibernate-orm-panache");
hasDependency(model, "quarkus-jdbc-postgresql");
}

@Test
void testRegexpMatches() throws IOException {
File pom = new File("target/extensions-test", "pom.xml");

CreateProjectTest.delete(pom.getParentFile());
new CreateProject(new FileProjectWriter(pom.getParentFile()))
.groupId("org.acme")
.artifactId("add-extension-test")
.version("0.0.1-SNAPSHOT")
.doCreateProject(new HashMap<>());

File pomFile = new File(pom.getAbsolutePath());
AddExtensionResult result = new AddExtensions(new FileProjectWriter(pomFile.getParentFile()))
.addExtensions(new HashSet<>(asList("SmallRye*")));

result.isUpdated();

Model model = MojoUtils.readPom(pom);
hasDependency(model, "quarkus-smallrye-reactive-messaging");
hasDependency(model, "quarkus-smallrye-reactive-streams-operators");
hasDependency(model, "quarkus-smallrye-opentracing");
hasDependency(model, "quarkus-smallrye-metrics");
hasDependency(model, "quarkus-smallrye-reactive-messaging-kafka");
hasDependency(model, "quarkus-smallrye-health");
hasDependency(model, "quarkus-smallrye-openapi");
hasDependency(model, "quarkus-smallrye-jwt");
hasDependency(model, "quarkus-smallrye-context-propagation");
hasDependency(model, "quarkus-smallrye-reactive-type-converters");
hasDependency(model, "quarkus-smallrye-reactive-messaging-amqp");
hasDependency(model, "quarkus-smallrye-fault-tolerance");
}

@Test
void addMissingExtension() throws IOException {
Expand Down Expand Up @@ -276,8 +308,8 @@ void testShortNameSelection() {
SelectionResult matches = AddExtensions.select("foo", extensions, false);
Assertions.assertTrue(matches.matches());
Assertions.assertEquals(1, matches.getExtensions().size());
Assertions.assertNotNull(matches.getMatch());
Assertions.assertTrue(matches.getMatch().getArtifactId().equalsIgnoreCase("some-complex-seo-unaware-artifactid"));
Assertions.assertTrue(matches.iterator().hasNext());
Assertions.assertTrue(matches.iterator().next().getArtifactId().equalsIgnoreCase("some-complex-seo-unaware-artifactid"));
}

@Test
Expand All @@ -297,8 +329,8 @@ void testArtifactIdSelectionWithQuarkusPrefix() {
Collections.shuffle(extensions);
SelectionResult matches = AddExtensions.select("foo", extensions, false);
Assertions.assertEquals(1, matches.getExtensions().size());
Assertions.assertNotNull(matches.getMatch());
Assertions.assertTrue(matches.getMatch().getArtifactId().equalsIgnoreCase("quarkus-foo"));
Assertions.assertTrue(matches.iterator().hasNext());
Assertions.assertTrue(matches.iterator().next().getArtifactId().equalsIgnoreCase("quarkus-foo"));
}

@Test
Expand Down

0 comments on commit a45828e

Please sign in to comment.