Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow * expression for quarkus:add-extension #3672

Merged
merged 1 commit into from
Aug 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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");
}
Dufgui marked this conversation as resolved.
Show resolved Hide resolved

@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