Skip to content

Commit

Permalink
Allow * expression for quarkus:add-extension
Browse files Browse the repository at this point in the history
fix quarkusio#1234

change to more complex test
  • Loading branch information
Dufgui committed Aug 24, 2019
1 parent f9ea1a8 commit 678942b
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 20 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
import static io.quarkus.maven.utilities.MojoUtils.readPom;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
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,17 +76,99 @@ 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 +215,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 @@ -64,6 +64,38 @@ void testPartialMatches() throws IOException {
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("Sm??lRye**")));

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 {
final File pom = new File("target/extensions-test", "pom.xml");
Expand Down Expand Up @@ -276,8 +308,9 @@ 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 +330,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
43 changes: 39 additions & 4 deletions docs/src/main/asciidoc/gradle-tooling.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ luckily setting up a Quarkus project with Gradle is very simple. You only need t
----
plugins {
id 'java'
id 'io.quarkus' version '{quarkus-version}'
}
apply plugin: 'io.quarkus'
----

or, if you use the Gradle Kotlin DSL:
Expand All @@ -28,8 +29,9 @@ or, if you use the Gradle Kotlin DSL:
----
plugins {
java
id("io.quarkus") version "{quarkus-version}"
}
apply(plugin = "io.quarkus")
----

=== Gradle configuration for a local SNAPSHOT version of Quarkus
Expand Down Expand Up @@ -87,8 +89,8 @@ Here's the same build script, using the Gradle Kotlin DSL:
----
plugins {
java
id("io.quarkus") version "{quarkus-version}"
}
apply(plugin = "io.quarkus")
repositories {
mavenCentral()
Expand Down Expand Up @@ -186,7 +188,40 @@ From inside a Quarkus project, you can obtain a list of the available extensions
./gradlew listExtensions
----

Functionality to automatically add extensions to your Gradle project is not implemented yet (coming soon).
You can enable an extension using:

[source,shell]
----
./gradlew addExtension --extensions="hibernate-validator"
----

Extensions are passed using a comma-separated list.

The extension name is the GAV name of the extension: e.g. `io.quarkus:quarkus-agroal`.
But you can pass a partial name and Quarkus will do its best to find the right extension.
For example, `agroal`, `Agroal` or `agro` will expand to `io.quarkus:quarkus-agroal`.
If no extension is found or if more than one extensions match, you will see a red check mark ❌ in the command result.

[source,shell]
----
./gradlew addExtension --extensions="jdbc,agroal,non-exist-ent"
[...]
❌ Multiple extensions matching 'jdbc'
* io.quarkus:quarkus-jdbc-h2
* io.quarkus:quarkus-jdbc-mariadb
* io.quarkus:quarkus-jdbc-postgresql
Be more specific e.g using the exact name or the full gav.
✅ Adding extension io.quarkus:quarkus-agroal
❌ Cannot find a dependency matching 'non-exist-ent', maybe a typo?
[...]
----

You can install all extensions wich match a globbing pattern :

[source,shell]
----
./gradlew addExtension --extensions="hibernate*"
----

== Development mode

Expand Down
7 changes: 7 additions & 0 deletions docs/src/main/asciidoc/maven-tooling.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,13 @@ $ ./mvnw quarkus:add-extensions -Dextensions=jdbc,agroal,non-exist-ent
[...]
----

You can install all extensions wich match a globbing pattern :

[source,shell]
----
./mvnw quarkus:add-extension -Dextensions="hibernate-*"
----

== Development mode

Quarkus comes with a built-in development mode.
Expand Down

0 comments on commit 678942b

Please sign in to comment.