Skip to content

Commit

Permalink
Defend against a missing WindowsRegistry service (#29068)
Browse files Browse the repository at this point in the history
  • Loading branch information
bot-gradle committed May 9, 2024
2 parents 24ea081 + 1749f57 commit 8920d62
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -405,29 +405,29 @@ protected WindowsRegistry createWindowsRegistry(OperatingSystem operatingSystem)
if (useNativeIntegrations && operatingSystem.isWindows()) {
return net.rubygrapefruit.platform.Native.get(WindowsRegistry.class);
}
return notAvailable(WindowsRegistry.class);
return notAvailable(WindowsRegistry.class, operatingSystem);
}

public SystemInfo createSystemInfo() {
public SystemInfo createSystemInfo(OperatingSystem operatingSystem) {
if (useNativeIntegrations) {
try {
return net.rubygrapefruit.platform.Native.get(SystemInfo.class);
} catch (NativeIntegrationUnavailableException e) {
LOGGER.debug("Native-platform system info is not available. Continuing with fallback.");
}
}
return notAvailable(SystemInfo.class);
return notAvailable(SystemInfo.class, operatingSystem);
}

protected Memory createMemory() {
protected Memory createMemory(OperatingSystem operatingSystem) {
if (useNativeIntegrations) {
try {
return net.rubygrapefruit.platform.Native.get(Memory.class);
} catch (NativeIntegrationUnavailableException e) {
LOGGER.debug("Native-platform memory integration is not available. Continuing with fallback.");
}
}
return notAvailable(Memory.class);
return notAvailable(Memory.class, operatingSystem);
}

protected ProcessLauncher createProcessLauncher() {
Expand All @@ -441,15 +441,15 @@ protected ProcessLauncher createProcessLauncher() {
return new DefaultProcessLauncher();
}

protected PosixFiles createPosixFiles() {
protected PosixFiles createPosixFiles(OperatingSystem operatingSystem) {
if (useNativeIntegrations) {
try {
return net.rubygrapefruit.platform.Native.get(PosixFiles.class);
} catch (NativeIntegrationUnavailableException e) {
LOGGER.debug("Native-platform posix files integration is not available. Continuing with fallback.");
}
}
return notAvailable(UnavailablePosixFiles.class);
return notAvailable(UnavailablePosixFiles.class, operatingSystem);
}

protected HostnameLookup createHostnameLookup() {
Expand Down Expand Up @@ -505,19 +505,19 @@ public boolean useFileSystemWatching() {
};
}

protected FileSystems createFileSystems() {
protected FileSystems createFileSystems(OperatingSystem operatingSystem) {
if (useNativeIntegrations) {
try {
return net.rubygrapefruit.platform.Native.get(FileSystems.class);
} catch (NativeIntegrationUnavailableException e) {
LOGGER.debug("Native-platform file systems information is not available. Continuing with fallback.");
}
}
return notAvailable(FileSystems.class);
return notAvailable(FileSystems.class, operatingSystem);
}

private <T> T notAvailable(Class<T> type) {
return Cast.uncheckedNonnullCast(Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[]{type}, new BrokenService(type.getSimpleName())));
private <T> T notAvailable(Class<T> type, OperatingSystem operatingSystem) {
return Cast.uncheckedNonnullCast(Proxy.newProxyInstance(type.getClassLoader(), new Class<?>[]{type}, new BrokenService(type.getSimpleName(), useNativeIntegrations, operatingSystem)));
}

private static String format(Throwable throwable) {
Expand All @@ -533,14 +533,18 @@ private static String format(Throwable throwable) {

private static class BrokenService implements InvocationHandler {
private final String type;
private final boolean useNativeIntegrations;
private final OperatingSystem operatingSystem;

private BrokenService(String type) {
private BrokenService(String type, boolean useNativeIntegrations, OperatingSystem operatingSystem) {
this.type = type;
this.useNativeIntegrations = useNativeIntegrations;
this.operatingSystem = operatingSystem;
}

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
throw new org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException(String.format("%s is not supported on this operating system.", type));
throw new org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException(String.format("Service '%s' is not available (os=%s, enabled=%s).", type, operatingSystem, useNativeIntegrations));
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import net.rubygrapefruit.platform.WindowsRegistry
import org.gradle.api.internal.file.temp.TemporaryFileProvider
import org.gradle.internal.file.Chmod
import org.gradle.internal.file.Stat
import org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException
import org.gradle.internal.nativeintegration.ProcessEnvironment
import org.gradle.internal.nativeintegration.console.ConsoleDetector
import org.gradle.internal.nativeintegration.filesystem.FileCanonicalizer
import org.gradle.internal.nativeintegration.filesystem.FileSystem
import org.gradle.internal.os.OperatingSystem
import org.gradle.test.precondition.Requires
import org.gradle.test.preconditions.UnitTestPreconditions
import org.gradle.util.UsesNativeServices
import spock.lang.Specification

Expand Down Expand Up @@ -83,4 +86,14 @@ class NativeServicesTest extends Specification {
expect:
services.get(TemporaryFileProvider) != null
}

@Requires(UnitTestPreconditions.NotWindows)
def "try using a WindowsRegistry on a non-Windows OS"() {
def service = services.get(WindowsRegistry)
when:
service.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, "SOFTWARE\\AdoptOpenJDK\\JDK")
then:
def e = thrown(NativeIntegrationUnavailableException)
e.message == "Service 'WindowsRegistry' is not available (os=${OperatingSystem.current()}, enabled=true)."
}
}
1 change: 1 addition & 0 deletions platforms/jvm/jvm-services/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ dependencies {
api(libs.nativePlatform)

implementation(project(":functional"))
implementation(project(":native"))

implementation(libs.guava)
implementation(libs.asm)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import com.google.common.collect.Lists;
import net.rubygrapefruit.platform.MissingRegistryEntryException;
import net.rubygrapefruit.platform.WindowsRegistry;
import org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException;
import org.gradle.internal.os.OperatingSystem;

import java.io.File;
Expand Down Expand Up @@ -67,9 +68,9 @@ private Set<InstallationLocation> findInstallationsInRegistry() {

private List<String> find(String sdkSubkey, String path, String value) {
try {
return getVersions(sdkSubkey).stream()
.map(version -> getValue(sdkSubkey, path, value, version)).collect(Collectors.toList());
} catch (MissingRegistryEntryException e) {
List<String> versions = getVersions(sdkSubkey);
return versions.stream().map(version -> getValue(sdkSubkey, path, value, version)).collect(Collectors.toList());
} catch (MissingRegistryEntryException | NativeIntegrationUnavailableException e) {
// Ignore
return Collections.emptyList();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ package org.gradle.jvm.toolchain.internal

import net.rubygrapefruit.platform.MissingRegistryEntryException
import net.rubygrapefruit.platform.WindowsRegistry
import org.gradle.api.internal.provider.Providers
import org.gradle.api.provider.ProviderFactory
import org.gradle.internal.nativeintegration.NativeIntegrationUnavailableException
import org.gradle.internal.os.OperatingSystem
import spock.lang.Specification

Expand Down Expand Up @@ -74,8 +73,20 @@ class WindowsInstallationSupplierTest extends Specification {

def "handles absent adoptopenjdk keys"() {
given:
registry.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, "SOFTWARE\\AdoptOpenJDK\\JDK") >> { throw new MissingRegistryEntryException() }
def supplier = createSupplier(OperatingSystem.MAC_OS)
registry.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, _) >> { throw new MissingRegistryEntryException() }
def supplier = createSupplier()

when:
def locations = supplier.get()

then:
locations.isEmpty()
}

def "gracefully handles unavailable native integration"() {
given:
registry.getSubkeys(WindowsRegistry.Key.HKEY_LOCAL_MACHINE, _) >> { throw new NativeIntegrationUnavailableException() }
def supplier = createSupplier()

when:
def locations = supplier.get()
Expand Down Expand Up @@ -114,11 +125,4 @@ class WindowsInstallationSupplierTest extends Specification {
WindowsInstallationSupplier createSupplier(OperatingSystem os = OperatingSystem.WINDOWS) {
new WindowsInstallationSupplier(registry, os)
}

ProviderFactory createProviderFactory(String propertyValue) {
def providerFactory = Mock(ProviderFactory)
providerFactory.gradleProperty("org.gradle.java.installations.auto-detect") >> Providers.notDefined()
providerFactory
}

}

0 comments on commit 8920d62

Please sign in to comment.