Skip to content

Commit

Permalink
Merge pull request #16159 from gsmet/native-cli
Browse files Browse the repository at this point in the history
Preliminary work for native CLI
  • Loading branch information
gsmet authored Apr 8, 2021
2 parents 26de587 + f3ed24c commit 9e917d4
Show file tree
Hide file tree
Showing 6 changed files with 149 additions and 25 deletions.
71 changes: 71 additions & 0 deletions devtools/cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
</parent>
<modelVersion>4.0.0</modelVersion>

<properties>
<quarkus.package.type>uber-jar</quarkus.package.type>
</properties>

<artifactId>quarkus-cli</artifactId>
<name>Quarkus - Command Line Interface</name>
<description>Quarkus command line utility</description>
Expand All @@ -26,6 +30,34 @@
<groupId>io.quarkus</groupId>
<artifactId>quarkus-project-core-extension-codestarts</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-apache-httpclient</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty</artifactId>
</dependency>
<!--
Somehow, we need this as otherwise you end up with:
java.lang.ClassNotFoundException: io.netty.handler.codec.http2.DefaultHttp2FrameWriter
as we try to initialize them at runtime anyway
which is weird because the NettyProcessor correctly checks if the HTTP2 support is around.
Note that if you drop this dependency, the native image build will finish,
but the native image will be all broken.
-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http2</artifactId>
</dependency>
<dependency>
<groupId>org.jboss.logmanager</groupId>
<artifactId>log4j-jboss-logmanager</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-devtools</artifactId>
Expand Down Expand Up @@ -55,6 +87,45 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-jackson-deployment</artifactId>
<type>pom</type>
<scope>test</scope>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-netty-deployment</artifactId>
<type>pom</type>
<scope>test</scope>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-apache-httpclient-deployment</artifactId>
<type>pom</type>
<scope>test</scope>
<version>${project.version}</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,22 +17,35 @@ public static String version() {
if (version != null) {
return version;
}
final URL quarkusPropsUrl = Thread.currentThread().getContextClassLoader().getResource("quarkus.properties");
if (quarkusPropsUrl == null) {

final Properties props = new Properties();
final URL quarkusPropertiesUrl = Thread.currentThread().getContextClassLoader().getResource("quarkus.properties");
if (quarkusPropertiesUrl == null) {
throw new RuntimeException("Failed to locate quarkus.properties on the classpath");
}
final Properties props = new Properties();
ClassPathUtils.consumeAsPath(quarkusPropsUrl, p -> {
try (BufferedReader reader = Files.newBufferedReader(p)) {
props.load(reader);

// we have a special case for file and jar as using getResourceAsStream() on Windows might cause file locks
if ("file".equals(quarkusPropertiesUrl.getProtocol()) || "jar".equals(quarkusPropertiesUrl.getProtocol())) {
ClassPathUtils.consumeAsPath(quarkusPropertiesUrl, p -> {
try (BufferedReader reader = Files.newBufferedReader(p)) {
props.load(reader);
} catch (IOException e) {
throw new RuntimeException("Failed to load quarkus.properties", e);
}
});
} else {
try {
props.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("quarkus.properties"));
} catch (IOException e) {
throw new RuntimeException("Failed to load quarkus.properties", e);
throw new IllegalStateException("Failed to load quarkus.properties", e);
}
});
}

version = props.getProperty("quarkus-core-version");
if (version == null) {
throw new RuntimeException("Failed to locate quarkus-core-version property in the bundled quarkus.properties");
}

return version;
}

Expand Down
50 changes: 50 additions & 0 deletions devtools/cli/src/main/java/io/quarkus/cli/core/Reflections.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package io.quarkus.cli.core;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection(targets = {
io.quarkus.devtools.codestarts.core.CodestartSpec.class,
io.quarkus.devtools.codestarts.core.CodestartSpec.LanguageSpec.class,
io.quarkus.devtools.codestarts.core.CodestartSpec.CodestartDep.class,
io.quarkus.registry.catalog.Category.class,
io.quarkus.registry.catalog.Extension.class,
io.quarkus.registry.catalog.ExtensionCatalog.class,
io.quarkus.registry.catalog.ExtensionOrigin.class,
io.quarkus.registry.catalog.json.JsonArtifactCoordsDeserializer.class,
io.quarkus.registry.catalog.json.JsonCategory.class,
io.quarkus.registry.catalog.json.JsonExtension.class,
io.quarkus.registry.catalog.json.JsonExtensionCatalog.class,
io.quarkus.registry.catalog.json.JsonExtensionOrigin.class,
org.apache.maven.repository.internal.DefaultArtifactDescriptorReader.class,
org.apache.maven.repository.internal.DefaultVersionRangeResolver.class,
org.apache.maven.repository.internal.DefaultVersionResolver.class,
org.apache.maven.repository.internal.SnapshotMetadataGeneratorFactory.class,
org.apache.maven.repository.internal.VersionsMetadataGeneratorFactory.class,
org.apache.maven.wagon.providers.http.HttpWagon.class,
org.apache.maven.wagon.shared.http.AbstractHttpClientWagon.class,
org.eclipse.aether.connector.basic.BasicRepositoryConnectorFactory.class,
org.eclipse.aether.internal.impl.DefaultArtifactResolver.class,
org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider.class,
org.eclipse.aether.internal.impl.DefaultDeployer.class,
org.eclipse.aether.internal.impl.DefaultFileProcessor.class,
org.eclipse.aether.internal.impl.DefaultInstaller.class,
org.eclipse.aether.internal.impl.DefaultLocalRepositoryProvider.class,
org.eclipse.aether.internal.impl.DefaultMetadataResolver.class,
org.eclipse.aether.internal.impl.DefaultOfflineController.class,
org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager.class,
org.eclipse.aether.internal.impl.DefaultRepositoryConnectorProvider.class,
org.eclipse.aether.internal.impl.DefaultRepositoryEventDispatcher.class,
org.eclipse.aether.internal.impl.DefaultRepositoryLayoutProvider.class,
org.eclipse.aether.internal.impl.DefaultRepositorySystem.class,
org.eclipse.aether.internal.impl.DefaultSyncContextFactory.class,
org.eclipse.aether.internal.impl.DefaultTransporterProvider.class,
org.eclipse.aether.internal.impl.DefaultUpdateCheckManager.class,
org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer.class,
org.eclipse.aether.internal.impl.EnhancedLocalRepositoryManagerFactory.class,
org.eclipse.aether.internal.impl.Maven2RepositoryLayoutFactory.class,
org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory.class,
org.eclipse.aether.internal.impl.collect.DefaultDependencyCollector.class,
org.eclipse.aether.transport.wagon.WagonTransporterFactory.class
})
public class Reflections {
}
6 changes: 2 additions & 4 deletions devtools/cli/src/main/resources/application.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
quarkus.log.level=WARN
quarkus.banner.enabled=false
quarkus.package.type=uber-jar
quarkus.native.additional-build-args=--allow-incomplete-classpath
#quarkus.native.auto-service-loader-registration=true
#quarkus.native.resources.includes=quarkus.properties,bundled-codestarts/**,codestarts/**
#quarkus.native.native-image-xmx=6g
quarkus.native.resources.includes=quarkus.properties
quarkus.native.additional-build-args=--initialize-at-run-time=org.apache.maven.wagon.shared.http.AbstractHttpClientWagon
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ class ApacheHttpClientProcessor {
@BuildStep
void runtimeInitializedClasses(BuildProducer<RuntimeInitializedClassBuildItem> runtimeInitializedClasses) {
runtimeInitializedClasses.produce(new RuntimeInitializedClassBuildItem("org.apache.http.impl.auth.NTLMEngineImpl"));
runtimeInitializedClasses
.produce(new RuntimeInitializedClassBuildItem("org.apache.http.conn.ssl.SSLConnectionSocketFactory"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.BooleanSupplier;
import java.util.stream.Collectors;

import org.jboss.jandex.AnnotationInstance;
Expand All @@ -25,23 +24,14 @@
import io.quarkus.deployment.builditem.nativeimage.NativeImageResourceBundleBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveClassBuildItem;
import io.quarkus.deployment.builditem.nativeimage.ReflectiveFieldBuildItem;
import io.quarkus.deployment.pkg.steps.NativeBuild;
import picocli.CommandLine;

public class PicocliNativeImageProcessor {

private static final Logger LOGGER = Logger.getLogger(PicocliNativeImageProcessor.class);

static class NativeImageProcessingEnabled implements BooleanSupplier {

PicocliDeploymentConfiguration deploymentConfiguration;

public boolean getAsBoolean() {
return deploymentConfiguration.nativeImageProcessingEnabled;
}

}

@BuildStep(onlyIf = NativeImageProcessingEnabled.class)
@BuildStep(onlyIf = NativeBuild.class)
void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<ReflectiveFieldBuildItem> reflectiveFields,
BuildProducer<ReflectiveClassBuildItem> reflectiveClasses,
Expand Down Expand Up @@ -104,7 +94,7 @@ void reflectionConfiguration(CombinedIndexBuildItem combinedIndexBuildItem,
foundFields.forEach(fieldInfo -> reflectiveFields.produce(new ReflectiveFieldBuildItem(fieldInfo)));
}

@BuildStep(onlyIf = NativeImageProcessingEnabled.class)
@BuildStep(onlyIf = NativeBuild.class)
void resourceBundlesConfiguration(CombinedIndexBuildItem combinedIndexBuildItem,
BuildProducer<NativeImageResourceBundleBuildItem> resourceBundles) {
combinedIndexBuildItem.getIndex().getAnnotations(DotName.createSimple(CommandLine.Command.class.getName()))
Expand Down

0 comments on commit 9e917d4

Please sign in to comment.