Skip to content

Commit

Permalink
Add toolchain detection for Nix package manager
Browse files Browse the repository at this point in the history
  • Loading branch information
lorenzleutgeb committed May 18, 2024
1 parent 766a628 commit 96648b9
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.gradle.jvm.toolchain.internal.IntellijInstallationSupplier;
import org.gradle.jvm.toolchain.internal.JabbaInstallationSupplier;
import org.gradle.jvm.toolchain.internal.JdkCacheDirectory;
import org.gradle.jvm.toolchain.internal.NixInstallationSupplier;
import org.gradle.jvm.toolchain.internal.LinuxInstallationSupplier;
import org.gradle.jvm.toolchain.internal.OsXInstallationSupplier;
import org.gradle.jvm.toolchain.internal.SdkmanInstallationSupplier;
Expand All @@ -58,6 +59,7 @@ public void configure(ServiceRegistration registration) {
registration.add(AsdfInstallationSupplier.class);
registration.add(IntellijInstallationSupplier.class);
registration.add(JabbaInstallationSupplier.class);
registration.add(NixInstallationSupplier.class);
registration.add(SdkmanInstallationSupplier.class);

// registration.add(MavenToolchainsInstallationSupplier.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ The following is a list of common package managers, tools, and locations that ar
JVM auto-detection knows how to work with:

* Operation-system specific locations: Linux, macOS, Windows
* Package Managers: https://asdf-vm.com/#/[Asdf-vm], https://github.com/shyiko/jabba[Jabba], https://sdkman.io/[SDKMAN!]
* Package Managers: https://asdf-vm.com/#/[Asdf-vm], https://github.com/shyiko/jabba[Jabba], https://nixos.org/nix[Nix], https://sdkman.io/[SDKMAN!]
* https://maven.apache.org/guides/mini/guide-using-toolchains.html[Maven Toolchain] specifications
* https://www.jetbrains.com/help/idea/sdk.html#jdk-from-ide[IntelliJ IDEA] installations

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
* Copyright 2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.gradle.jvm.toolchain.internal;

import com.google.common.annotations.VisibleForTesting;
import org.gradle.api.logging.Logger;
import org.gradle.api.logging.Logging;
import org.gradle.api.provider.Provider;
import org.gradle.api.provider.ProviderFactory;
import org.gradle.internal.os.OperatingSystem;

import java.io.File;
import java.io.FileFilter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;
import java.util.function.Predicate;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.inject.Inject;

public class NixInstallationSupplier implements InstallationSupplier {
private static final Logger LOGGER = Logging.getLogger(NixInstallationSupplier.class);

private static final String STORE_PATH_PROPERTY_NAME = "org.gradle.java.installations.nix.store";
private static final String STORE_PATH_DEFAULT = "/nix/store";

// Paths will be of the form "{hash}-{suffix}", for example:
//
// /nix/store/6375rn8kiq9pn4pgdkdiqgvg8b0gdycy-openjdk-19.0.2+7
//
// We know the the length of Nix store hashes (32),
// and the length of a hyphen (1), and only look at the suffix.
private static final int PREFIX_LENGTH = 33;

private static final Predicate<String> PATTERN = Pattern.compile("jdk", Pattern.CASE_INSENSITIVE).asPredicate();

private static final FileFilter FILTER = (final File file) -> {
final String name = file.getName();
if (name.length() < PREFIX_LENGTH) {
return false;
}
return PATTERN.test(name.substring(PREFIX_LENGTH));
};

@VisibleForTesting
final File store;

@Inject
public NixInstallationSupplier(ProviderFactory providerFactory) {
final OperatingSystem os = OperatingSystem.current();

// As of 2024-05, Nix is only officially supported on Linux and MacOS.
if (!os.isLinux() && !os.isMacOsX()) {
LOGGER.trace("Operating system not supported.");
store = null;
return;
}

File store = null;

final Provider<String> storeProvider = providerFactory.gradleProperty(STORE_PATH_PROPERTY_NAME);
if (storeProvider.isPresent()) {
try {
store = new File(storeProvider.get());
if (!store.exists()) {
store = null;
LOGGER.warn("Initialization for store path '{}' failed. Path does not exist. Falling back to default '{}'.", store, STORE_PATH_DEFAULT);
}
} catch (Exception e) {
store = null;
final String message = "Initialization for store path '{}' failed. Falling back to default '{}'.";
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(message, store, STORE_PATH_DEFAULT, e);
} else {
LOGGER.warn(message, store, STORE_PATH_DEFAULT);
}
}
if (store != null) {
this.store = store;
return;
}
}

try {
store = new File(STORE_PATH_DEFAULT);
if (!store.exists()) {
store = null;
LOGGER.debug("Initialization for default store path '{}' failed. Path does not exist.", STORE_PATH_DEFAULT);
}
} catch (Exception e) {
LOGGER.debug("Initialization for default store path '{}' failed.", STORE_PATH_DEFAULT, e);
}

this.store = store;
}

@Override
public Set<InstallationLocation> get() {
if (store == null) {
LOGGER.trace("Nothing to do since `store` is `null`.");
return Collections.emptySet();
}

final File[] list = store.listFiles(FILTER);
if (list == null) {
LOGGER.debug("Listing files within store path '{}' failed.");
return Collections.emptySet();
}

final HashSet<InstallationLocation> locations = new HashSet<InstallationLocation>(list.length);
for (final File file : list) {
locations.add(InstallationLocation.autoDetected(file, getSourceName()));
}
return locations;
}

@Override
public String getSourceName() {
return "Nix";
}

@VisibleForTesting
NixInstallationSupplier(File store) {
this.store = store;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.gradle.jvm.toolchain.internal.JavaToolchainQueryService;
import org.gradle.jvm.toolchain.internal.JdkCacheDirectory;
import org.gradle.jvm.toolchain.internal.LinuxInstallationSupplier;
import org.gradle.jvm.toolchain.internal.NixInstallationSupplier;
import org.gradle.jvm.toolchain.internal.MavenToolchainsInstallationSupplier;
import org.gradle.jvm.toolchain.internal.OsXInstallationSupplier;
import org.gradle.jvm.toolchain.internal.SdkmanInstallationSupplier;
Expand Down Expand Up @@ -95,6 +96,7 @@ public void configure(ServiceRegistration registration) {
registration.add(IntellijInstallationSupplier.class);
registration.add(JabbaInstallationSupplier.class);
registration.add(SdkmanInstallationSupplier.class);
registration.add(NixInstallationSupplier.class);
registration.add(MavenToolchainsInstallationSupplier.class);

registration.add(LinuxInstallationSupplier.class);
Expand Down

0 comments on commit 96648b9

Please sign in to comment.