Skip to content

Commit

Permalink
Check Java Toolchain install folder for left-overs (backport #22819)
Browse files Browse the repository at this point in the history
  • Loading branch information
jbartok committed Dec 8, 2022
1 parent b668172 commit 0421be5
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,21 @@ public Throwable getErrorCause() {
public boolean isValidInstallation() {
return true;
}

@Override
public String toString() {
return "DefaultJvmInstallationMetadata{" +
"languageVersion=" + languageVersion +
", javaVersion='" + javaVersion + '\'' +
", javaVendor='" + javaVendor + '\'' +
", runtimeName='" + runtimeName + '\'' +
", runtimeVersion='" + runtimeVersion + '\'' +
", jvmName='" + jvmName + '\'' +
", jvmVersion='" + jvmVersion + '\'' +
", jvmVendor='" + jvmVendor + '\'' +
", architecture='" + architecture + '\'' +
'}';
}
}

class FailureInstallationMetadata implements JvmInstallationMetadata {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,8 @@ class JavaToolchainDownloadSpiAuthenticationIntegrationTest extends AbstractJava
.assertHasCause("Error while evaluating property 'javaCompiler' of task ':compileJava'.")
.assertHasCause("Failed to calculate the value of task ':compileJava' property 'javaCompiler'.")
.assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=matching('exotic'), implementation=vendor-specific}) from '" + archiveUri + "'.")
.assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed.")
.assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed: " +
"A problem occurred starting process 'command '")
}

@ToBeFixedForConfigurationCache(because = "Fails the build with an additional error")
Expand Down Expand Up @@ -135,7 +136,8 @@ class JavaToolchainDownloadSpiAuthenticationIntegrationTest extends AbstractJava
.assertHasCause("Error while evaluating property 'javaCompiler' of task ':compileJava'")
.assertHasCause("Failed to calculate the value of task ':compileJava' property 'javaCompiler'.")
.assertHasCause("Unable to download toolchain matching the requirements ({languageVersion=99, vendor=matching('exotic'), implementation=vendor-specific}) from '" + archiveUri + "'.")
.assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed.")
.assertHasCause("Provisioned toolchain '" + temporaryFolder.testDirectory.file("user-home", "jdks", "toolchain") + "' could not be probed: " +
"A problem occurred starting process 'command '")
}

private static String customToolchainResolverCode(String uri) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,32 +118,101 @@ private File getJavaHome(File markedLocation) {
* Unpacks and installs the given JDK archive. Returns a file pointing to the java home directory.
*/
public File provisionFromArchive(JavaToolchainSpec spec, File jdkArchive, URI uri) {
final File unpackFolder = unpack(jdkArchive);
File markedLocation = markedLocation(unpackFolder);
markAsReady(markedLocation);
final File[] unpackFolder = new File[1];
final File[] installFolder = new File[1];
try {
unpackFolder[0] = unpack(jdkArchive);

//put the marker file in the unpack folder from where it will get in its proper place
//when the contents are copied to the installation folder
File markedLocation = markLocationInsideFolder(unpackFolder[0]);

//probe unpacked installation for its metadata
JvmInstallationMetadata metadata = getMetadata(markedLocation);

validateMetadataMatchesSpec(spec, uri, metadata);

String installFolderName = getInstallFolderName(metadata);
installFolder[0] = new File(jdkDirectory, installFolderName);

//make sure the install folder is empty
checkInstallFolderForLeftoverContent(installFolder[0], uri, spec, metadata);
operations.delete(installFolder[0]);

//copy content of unpack folder to install folder, including the marker file
operations.copy(copySpec -> {
copySpec.from(unpackFolder[0]);
copySpec.into(installFolder[0]);
});

LOGGER.info("Installed toolchain from {} into {}", uri, installFolder[0]);
return getJavaHome(markedLocation(installFolder[0]));
} catch (Throwable t) {
// provisioning failed, clean up leftovers
if (installFolder[0] != null) {
operations.delete(installFolder[0]);
}
throw t;
} finally {
// clean up temporary unpack folder, regardless if provisioning succeeded or not
if (unpackFolder[0] != null) {
operations.delete(unpackFolder[0]);
}
}
}

private void checkInstallFolderForLeftoverContent(File installFolder, URI uri, JavaToolchainSpec spec, JvmInstallationMetadata metadata) {
if (!installFolder.exists()) {
return; //install folder doesn't even exist
}

File[] filesInInstallFolder = installFolder.listFiles();
if (filesInInstallFolder == null || filesInInstallFolder.length == 0) {
return; //no files in install folder
}

File markerLocation = markedLocation(installFolder);
if (!isMarkedLocation(markerLocation)) {
return; //no marker found
}

String leftoverMetadata;
try {
leftoverMetadata = getMetadata(markerLocation).toString();
} catch (Exception e) {
LOGGER.debug("Failed determining metadata of installation leftover", e);
leftoverMetadata = "Could not be determined due to: " + e.getMessage();
}
LOGGER.warn("While provisioning Java toolchain from '{}' to satisfy spec '{}' (with metadata '{}'), " +
"leftover content (with metadata '{}') was found in the install folder '{}'. " +
"The existing installation will be replaced by the new download.",
uri, spec, metadata, leftoverMetadata, installFolder);
}

private JvmInstallationMetadata getMetadata(File markedLocation) {
File javaHome = getJavaHome(markedLocation);

JvmInstallationMetadata metadata = detector.getMetadata(new InstallationLocation(javaHome, "provisioned toolchain"));
if (!metadata.isValidInstallation()) {
throw new GradleException("Provisioned toolchain '" + javaHome + "' could not be probed.");
}
if (!new JavaToolchainMatcher(spec).test(metadata)) {
throw new GradleException("Toolchain provisioned from '" + uri + "' doesn't satisfy the specification: " + spec.getDisplayName() + ".");
throw new GradleException("Provisioned toolchain '" + javaHome + "' could not be probed: " + metadata.getErrorMessage(), metadata.getErrorCause());
}

File installFolder = new File(jdkDirectory, toDirectoryName(metadata));
operations.copy(copySpec -> {
copySpec.from(unpackFolder);
copySpec.into(installFolder);
});
operations.delete(unpackFolder);
return metadata;
}

LOGGER.info("Installed toolchain from {} into {}", uri, installFolder);
private File markLocationInsideFolder(File unpackedInstallationFolder) {
File markedLocation = markedLocation(unpackedInstallationFolder);
markAsReady(markedLocation);
return markedLocation;
}

return getJavaHome(markedLocation(installFolder));
private static void validateMetadataMatchesSpec(JavaToolchainSpec spec, URI uri, JvmInstallationMetadata metadata) {
if (!new JavaToolchainMatcher(spec).test(metadata)) {
throw new GradleException("Toolchain provisioned from '" + uri + "' doesn't satisfy the specification: " + spec.getDisplayName() + ".");
}
}

private static String toDirectoryName(JvmInstallationMetadata metadata) {
private static String getInstallFolderName(JvmInstallationMetadata metadata) {
String vendor = metadata.getJvmVendor();
if (vendor == null || vendor.isEmpty()) {
vendor = metadata.getVendor().getRawVendor();
Expand Down

0 comments on commit 0421be5

Please sign in to comment.