Skip to content

Commit

Permalink
Add Gradle rich output support, configure default metadata URL on Mav…
Browse files Browse the repository at this point in the history
…en (#249)

This PR does the following:

- Adds Gradle rich output support (color and links in `native-image` output are enabled by default on supported platforms)
- Default metadata repository URL moved to common constants
- Added default metadata repository URL to Maven plugin
- Renames JVM reachability metadata to GraalVM reachability metadata
  • Loading branch information
lazar-mitrovic committed Jun 15, 2022
2 parents 1994d2d + b96b007 commit a9b5900
Show file tree
Hide file tree
Showing 15 changed files with 74 additions and 54 deletions.
Expand Up @@ -55,7 +55,7 @@
* and provide overrides for cases where configuration files
* are missing.
*/
public interface JvmReachabilityMetadataRepository {
public interface GraalVMReachabilityMetadataRepository {
/**
* Performs a generic query on the repository, returning a list of
* configuration directories. The query may be parameterized with
Expand Down
Expand Up @@ -40,7 +40,7 @@
*/
package org.graalvm.reachability.internal;

import org.graalvm.reachability.JvmReachabilityMetadataRepository;
import org.graalvm.reachability.GraalVMReachabilityMetadataRepository;
import org.graalvm.reachability.Query;
import org.graalvm.reachability.internal.index.artifacts.SingleModuleJsonVersionToConfigDirectoryIndex;
import org.graalvm.reachability.internal.index.artifacts.VersionToConfigDirectoryIndex;
Expand All @@ -55,7 +55,7 @@
import java.util.function.Supplier;
import java.util.stream.Collectors;

public class FileSystemRepository implements JvmReachabilityMetadataRepository {
public class FileSystemRepository implements GraalVMReachabilityMetadataRepository {

private final FileSystemModuleToConfigDirectoryIndex moduleIndex;
private final Logger logger;
Expand Down
Expand Up @@ -51,6 +51,9 @@
*/
public interface SharedConstants {
boolean IS_WINDOWS = System.getProperty("os.name", "unknown").contains("Windows");
boolean IS_CI = System.getenv("CI") != null;
boolean IS_DUMB_TERM = Arrays.asList(null, "", "dumb", "unknown").contains(System.getenv("TERM"));
boolean NO_COLOR = System.getenv("NO_COLOR") != null; // https://no-color.org/
String GRAALVM_EXE_EXTENSION = (IS_WINDOWS ? ".cmd" : "");
String EXECUTABLE_EXTENSION = (IS_WINDOWS ? ".exe" : "");
String NATIVE_IMAGE_EXE = "native-image" + GRAALVM_EXE_EXTENSION;
Expand All @@ -72,4 +75,5 @@ public interface SharedConstants {
String AGENT_SESSION_SUBDIR = "session-{pid}-{datetime}";
String AGENT_OUTPUT_DIRECTORY_MARKER = "{output_dir}";
String AGENT_OUTPUT_DIRECTORY_OPTION = "config-output-dir=";
String METADATA_REPO_URL_TEMPLATE = "https://github.com/graalvm/graalvm-reachability-metadata/releases/download/%1$s/graalvm-reachability-metadata-%1$s.zip";
}
2 changes: 1 addition & 1 deletion docs/src/docs/asciidoc/maven-plugin.adoc
Expand Up @@ -615,7 +615,7 @@ automatically added to your native build options.
[[metadata-support]]
== GraalVM Reachability Metadata Support

Since release 0.9.12, the plugin adds experimental support for the https://github.com/graalvm/jvm-reachability-metadata/[JVM reachability metadata repository].
Since release 0.9.12, the plugin adds experimental support for the https://github.com/graalvm/graalvm-reachability-metadata/[GraalVM reachability metadata repository].
This repository provides GraalVM metadata for libraries which do not officially support GraalVM native.

A metadata repository consists of configuration files for GraalVM.
Expand Down
1 change: 1 addition & 0 deletions docs/src/docs/snippets/gradle/groovy/build.gradle
Expand Up @@ -120,6 +120,7 @@ graalvmNative {
fallback = true // Sets the fallback mode of native-image, defaults to false
sharedLibrary = false // Determines if image is a shared library, defaults to false if `java-library` plugin isn't included
quickBuild = false // Determines if image is being built in quick build mode (alternatively use GRAALVM_QUICK_BUILD environment variable)
richOutput = false // Determines if native-image building should be done with rich output

systemProperties = [name1: 'value1', name2: 'value2'] // Sets the system properties to use for the native image builder
configurationFileDirectories.from(file('src/my-config')) // Adds a native image configuration file directory, containing files like reflection configuration
Expand Down
1 change: 1 addition & 0 deletions docs/src/docs/snippets/gradle/kotlin/build.gradle.kts
Expand Up @@ -78,6 +78,7 @@ graalvmNative {
fallback.set(true) // Sets the fallback mode of native-image, defaults to false
sharedLibrary.set(false) // Determines if image is a shared library, defaults to false if `java-library` plugin isn't included
quickBuild.set(false) // Determines if image is being built in quick build mode (alternatively use GRAALVM_QUICK_BUILD environment variable)
richOutput.set(false) // Determines if native-image building should be done with rich output

systemProperties.putAll(mapOf("name1" to "value1", "name2" to "value2")) // Sets the system properties to use for the native image builder
configurationFileDirectories.from(file("src/my-config")) // Adds a native image configuration file directory, containing files like reflection configuration
Expand Down
Expand Up @@ -75,10 +75,10 @@ class NativeConfigRepoFunctionalTest extends AbstractFunctionalTest {
outputContains "Hello, from reflection!"

and: "doesn't find a configuration directory for the current version"
outputContains "[jvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory not found. Trying latest version."
outputContains "[graalvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory not found. Trying latest version."

and: "but finds one thanks to the latest configuration field"
outputContains "[jvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory is org/graalvm/internal/library-with-reflection/1"
outputContains "[graalvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory is org/graalvm/internal/library-with-reflection/1"

where:
format | label
Expand Down Expand Up @@ -112,7 +112,7 @@ graalvmNative {
outputContains "Reflection failed"

and: "doesn't look for a configuration directory for the current version"
outputDoesNotContain "[jvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory not found. Trying latest version."
outputDoesNotContain "[graalvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration directory not found. Trying latest version."
}

def "can force a dependency to a specific config version"() {
Expand All @@ -139,7 +139,7 @@ graalvmNative {
outputContains "Reflection failed"

and: "looks for specific configuration version"
outputContains "[jvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration is forced to version 2"
outputContains "[graalvm reachability metadata repository for org.graalvm.internal:library-with-reflection:1.5]: Configuration is forced to version 2"
}

}
Expand Up @@ -45,7 +45,7 @@
import org.graalvm.buildtools.agent.AgentConfiguration;
import org.graalvm.buildtools.agent.AgentMode;
import org.graalvm.buildtools.gradle.dsl.GraalVMExtension;
import org.graalvm.buildtools.gradle.dsl.JvmReachabilityMetadataRepositoryExtension;
import org.graalvm.buildtools.gradle.dsl.GraalVMReachabilityMetadataRepositoryExtension;
import org.graalvm.buildtools.gradle.dsl.NativeImageOptions;
import org.graalvm.buildtools.gradle.dsl.agent.AgentOptions;
import org.graalvm.buildtools.gradle.internal.AgentCommandLineProvider;
Expand All @@ -55,7 +55,7 @@
import org.graalvm.buildtools.gradle.internal.DeprecatedNativeImageOptions;
import org.graalvm.buildtools.gradle.internal.GraalVMLogger;
import org.graalvm.buildtools.gradle.internal.GradleUtils;
import org.graalvm.buildtools.gradle.internal.JvmReachabilityMetadataService;
import org.graalvm.buildtools.gradle.internal.GraalVMReachabilityMetadataService;
import org.graalvm.buildtools.gradle.internal.NativeConfigurations;
import org.graalvm.buildtools.gradle.internal.agent.AgentConfigurationFactory;
import org.graalvm.buildtools.gradle.tasks.BuildNativeImageTask;
Expand Down Expand Up @@ -129,6 +129,7 @@
import static org.graalvm.buildtools.gradle.internal.NativeImageExecutableLocator.graalvmHomeProvider;
import static org.graalvm.buildtools.utils.SharedConstants.AGENT_PROPERTY;
import static org.graalvm.buildtools.utils.SharedConstants.IS_WINDOWS;
import static org.graalvm.buildtools.utils.SharedConstants.METADATA_REPO_URL_TEMPLATE;

/**
* Gradle plugin for GraalVM Native Image.
Expand Down Expand Up @@ -307,10 +308,10 @@ private void configureAutomaticTaskCreation(Project project,
}

private void configureJvmReachabilityConfigurationDirectories(Project project, GraalVMExtension graalExtension, NativeImageOptions options, SourceSet sourceSet) {
JvmReachabilityMetadataRepositoryExtension repositoryExtension = reachabilityExtensionOn(graalExtension);
Provider<JvmReachabilityMetadataService> serviceProvider = project.getGradle()
GraalVMReachabilityMetadataRepositoryExtension repositoryExtension = reachabilityExtensionOn(graalExtension);
Provider<GraalVMReachabilityMetadataService> serviceProvider = project.getGradle()
.getSharedServices()
.registerIfAbsent("nativeConfigurationService", JvmReachabilityMetadataService.class, spec -> {
.registerIfAbsent("nativeConfigurationService", GraalVMReachabilityMetadataService.class, spec -> {
LogLevel logLevel = determineLogLevel();
spec.getParameters().getLogLevel().set(logLevel);
spec.getParameters().getUri().set(repositoryExtension.getUri());
Expand Down Expand Up @@ -353,8 +354,8 @@ private static LogLevel determineLogLevel() {
return logLevel;
}

private static JvmReachabilityMetadataRepositoryExtension reachabilityExtensionOn(GraalVMExtension graalExtension) {
return ((ExtensionAware) graalExtension).getExtensions().getByType(JvmReachabilityMetadataRepositoryExtension.class);
private static GraalVMReachabilityMetadataRepositoryExtension reachabilityExtensionOn(GraalVMExtension graalExtension) {
return ((ExtensionAware) graalExtension).getExtensions().getByType(GraalVMReachabilityMetadataRepositoryExtension.class);
}

private void deprecateExtension(Project project,
Expand Down Expand Up @@ -419,11 +420,11 @@ private GraalVMExtension registerGraalVMExtension(Project project) {
}

private void configureNativeConfigurationRepo(ExtensionAware graalvmNative) {
JvmReachabilityMetadataRepositoryExtension configurationRepository = graalvmNative.getExtensions().create("metadataRepository", JvmReachabilityMetadataRepositoryExtension.class);
GraalVMReachabilityMetadataRepositoryExtension configurationRepository = graalvmNative.getExtensions().create("metadataRepository", GraalVMReachabilityMetadataRepositoryExtension.class);
configurationRepository.getEnabled().convention(false);
configurationRepository.getUri().convention(configurationRepository.getVersion().map(v -> {
try {
return new URI("https://github.com/graalvm/graalvm-reachability-metadata/releases/download/" + v + "/graalvm-reachability-metadata-" + v + ".zip");
return new URI(String.format(METADATA_REPO_URL_TEMPLATE, v));
} catch (URISyntaxException e) {
return null;
}
Expand Down
Expand Up @@ -49,18 +49,18 @@
import java.net.URISyntaxException;

/**
* Extension used to configure the JVM reachability metadata repository.
* Extension used to configure the GraalVM reachability metadata repository.
*/
public interface JvmReachabilityMetadataRepositoryExtension {
public interface GraalVMReachabilityMetadataRepositoryExtension {
/**
* Property used to determine if the native configuration
* Property used to determine if the reachability metadata
* repository should be used.
* @return the enabled property
*/
Property<Boolean> getEnabled();

/**
* A URI pointing to a jvm reachability metadata repository. This must
* A URI pointing to a GraalVM reachability metadata repository. This must
* either be a local file or a remote URI. In case of remote
* files, only zip or tarballs are supported.
* @return the uri property
Expand All @@ -70,8 +70,8 @@ public interface JvmReachabilityMetadataRepositoryExtension {
/**
* An optional version of the remote repository: if specified,
* and that no URI is provided, it will automatically use a
* published repository from the official GraalVM configuration
* repository.
* published repository from the official GraalVM reachability
* metadata repository.
*
* @return the version of the repository to use
*/
Expand Down
Expand Up @@ -171,6 +171,14 @@ public interface NativeImageOptions extends Named {
@Input
Property<Boolean> getQuickBuild();

/**
* Gets the value which determines if image is being built with rich output.
*
* @return The value which determines if image is being built with rich output.
*/
@Input
Property<Boolean> getRichOutput();

/**
* Returns the toolchain used to invoke native-image. Currently pointing
* to a Java launcher due to Gradle limitations.
Expand Down
Expand Up @@ -44,6 +44,7 @@
import org.graalvm.buildtools.gradle.dsl.NativeImageOptions;
import org.graalvm.buildtools.gradle.dsl.NativeResourcesOptions;
import org.graalvm.buildtools.gradle.dsl.agent.DeprecatedAgentOptions;
import org.graalvm.buildtools.utils.SharedConstants;
import org.gradle.api.Action;
import org.gradle.api.file.ConfigurableFileCollection;
import org.gradle.api.model.ObjectFactory;
Expand Down Expand Up @@ -186,6 +187,14 @@ public String getName() {
@Input
public abstract Property<Boolean> getQuickBuild();

/**
* Gets the value which determines if image is being built with rich output.
*
* @return The value which determines if image is being built with rich output.
*/
@Input
public abstract Property<Boolean> getRichOutput();

/**
* Returns the toolchain used to invoke native-image. Currently, pointing
* to a Java launcher due to Gradle limitations.
Expand All @@ -195,7 +204,7 @@ public String getName() {
public abstract Property<JavaLauncher> getJavaLauncher();

/**
* Returns the list of configuration file directories (e.g resource-config.json, ...) which need
* Returns the list of configuration file directories (e.g. resource-config.json, ...) which need
* to be passed to native-image.
*
* @return a collection of directories
Expand Down Expand Up @@ -232,14 +241,14 @@ public BaseNativeImageOptions(String name,
getFallback().convention(false);
getVerbose().convention(false);
getQuickBuild().convention(false);
getRichOutput().convention(!SharedConstants.IS_CI && !SharedConstants.IS_WINDOWS && !SharedConstants.IS_DUMB_TERM && !SharedConstants.NO_COLOR);
getSharedLibrary().convention(false);
getImageName().convention(defaultImageName);
getUseFatJar().convention(false);
}

private static Provider<Boolean> property(ProviderFactory providers, String name) {
return providers.gradleProperty(name)
.forUseAtConfigurationTime()
.map(Boolean::valueOf)
.orElse(false);
}
Expand Down
Expand Up @@ -40,7 +40,7 @@
*/
package org.graalvm.buildtools.gradle.internal;

import org.graalvm.reachability.JvmReachabilityMetadataRepository;
import org.graalvm.reachability.GraalVMReachabilityMetadataRepository;
import org.graalvm.reachability.Query;
import org.graalvm.reachability.internal.FileSystemRepository;
import org.gradle.api.file.ArchiveOperations;
Expand All @@ -57,12 +57,12 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
Expand All @@ -72,10 +72,10 @@
import java.util.function.Consumer;
import java.util.function.Supplier;

public abstract class JvmReachabilityMetadataService implements BuildService<JvmReachabilityMetadataService.Params>, JvmReachabilityMetadataRepository {
private static final Logger LOGGER = Logging.getLogger(JvmReachabilityMetadataService.class);
public abstract class GraalVMReachabilityMetadataService implements BuildService<GraalVMReachabilityMetadataService.Params>, GraalVMReachabilityMetadataRepository {
private static final Logger LOGGER = Logging.getLogger(GraalVMReachabilityMetadataService.class);

private final JvmReachabilityMetadataRepository repository;
private final GraalVMReachabilityMetadataRepository repository;

@Inject
protected abstract ArchiveOperations getArchiveOperations();
Expand All @@ -91,27 +91,27 @@ public interface Params extends BuildServiceParameters {
DirectoryProperty getCacheDir();
}

public JvmReachabilityMetadataService() throws URISyntaxException {
public GraalVMReachabilityMetadataService() throws URISyntaxException {
URI uri = getParameters().getUri().get();
this.repository = newRepository(uri);
}

private static String hashFor(URI uri) {
try {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] messageDigest = md.digest(md.digest(uri.toString().getBytes("utf-8")));
byte[] messageDigest = md.digest(md.digest(uri.toString().getBytes(StandardCharsets.UTF_8)));
BigInteger no = new BigInteger(1, messageDigest);
StringBuilder digest = new StringBuilder(no.toString(16));
while (digest.length() < 32) {
digest.insert(0, "0");
}
return digest.toString();
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
} catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException(e);
}
}

private JvmReachabilityMetadataRepository newRepository(URI uri) throws URISyntaxException {
private GraalVMReachabilityMetadataRepository newRepository(URI uri) throws URISyntaxException {
String cacheKey = hashFor(uri);
String path = uri.getPath();
LogLevel logLevel = getParameters().getLogLevel().get();
Expand Down Expand Up @@ -163,11 +163,11 @@ private FileSystemRepository newRepositoryFromDirectory(Path path, LogLevel logL
return new FileSystemRepository(path, new FileSystemRepository.Logger() {
@Override
public void log(String groupId, String artifactId, String version, Supplier<String> message) {
LOGGER.log(logLevel, "[jvm reachability metadata repository for {}:{}:{}]: {}", groupId, artifactId, version, message.get());
LOGGER.log(logLevel, "[graalvm reachability metadata repository for {}:{}:{}]: {}", groupId, artifactId, version, message.get());
}
});
} else {
throw new IllegalArgumentException("JVM reachability metadata repository URI must point to a directory");
throw new IllegalArgumentException("GraalVM reachability metadata repository URI must point to a directory");
}
}

Expand Down
Expand Up @@ -112,6 +112,7 @@ public List<String> asArguments() {
appendBooleanOption(cliArgs, options.getVerbose(), "--verbose");
appendBooleanOption(cliArgs, options.getSharedLibrary(), "--shared");
appendBooleanOption(cliArgs, options.getQuickBuild(), "-Ob");
appendBooleanOption(cliArgs, options.getRichOutput(), "-H:+BuildOutputColorful");

if (getOutputDirectory().isPresent()) {
cliArgs.add("-H:Path=" + getOutputDirectory().get());
Expand Down

0 comments on commit a9b5900

Please sign in to comment.