Skip to content

Commit

Permalink
Try use vertx webclient to install Node.js
Browse files Browse the repository at this point in the history
  • Loading branch information
ia3andy committed Sep 22, 2023
1 parent 65a820f commit 50f311f
Show file tree
Hide file tree
Showing 4 changed files with 170 additions and 23 deletions.
2 changes: 1 addition & 1 deletion .github/project.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
release:
current-version: 2.2.0.CR1
current-version: 2.1.0
next-version: 999-SNAPSHOT

Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.github.eirslett.maven.plugins.frontend.lib;

import java.io.File;
import java.nio.file.Path;

import io.vertx.core.Vertx;

public class PackageManagerInstallFactory {

private static final Platform defaultPlatform = Platform.guess();
private static final String DEFAULT_CACHE_PATH = "cache";
private final Vertx vertx;
private final Path installDirectory;
private final CacheResolver cacheResolver;
private final VertxFileDownloader fileDownloader;

public PackageManagerInstallFactory(Vertx vertx, Path installDirectory) {
this.vertx = vertx;
this.installDirectory = installDirectory;
this.cacheResolver = getDefaultCacheResolver(installDirectory);
fileDownloader = new VertxFileDownloader(vertx);
}

public NodeInstaller getNodeInstaller() {

return new NodeInstaller(this.getInstallConfig(), new DefaultArchiveExtractor(), fileDownloader);
}

public NPMInstaller getNPMInstaller() {
return new NPMInstaller(this.getInstallConfig(), new DefaultArchiveExtractor(), fileDownloader);
}

public PnpmInstaller getPnpmInstaller() {
return new PnpmInstaller(this.getInstallConfig(), new DefaultArchiveExtractor(), fileDownloader);
}

public YarnInstaller getYarnInstaller() {
return new YarnInstaller(this.getInstallConfig(), new DefaultArchiveExtractor(), fileDownloader);
}

private NodeExecutorConfig getExecutorConfig() {
return new InstallNodeExecutorConfig(this.getInstallConfig());
}

private InstallConfig getInstallConfig() {
final File installDirFile = this.installDirectory.toFile();
return new DefaultInstallConfig(installDirFile, installDirFile, this.cacheResolver, defaultPlatform);
}

private static final CacheResolver getDefaultCacheResolver(Path root) {
return new DirectoryCacheResolver(root.resolve("cache").toFile());
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package com.github.eirslett.maven.plugins.frontend.lib;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FilenameUtils;
import org.jboss.logging.Logger;

import io.vertx.core.Future;
import io.vertx.core.Vertx;
import io.vertx.core.buffer.Buffer;
import io.vertx.ext.web.client.HttpRequest;
import io.vertx.ext.web.client.HttpResponse;
import io.vertx.ext.web.client.WebClient;
import io.vertx.ext.web.client.WebClientOptions;

public class VertxFileDownloader implements FileDownloader {
private static final Logger LOG = Logger.getLogger(VertxFileDownloader.class);
private final Vertx vertx;
private WebClient webClient;

public VertxFileDownloader(Vertx vertx) {
this.vertx = vertx;
webClient = WebClient.create(vertx, new WebClientOptions()
.setSsl(true)
.setFollowRedirects(true)
.setTrustAll(true)
.setKeepAlive(true));
}

public void download(String downloadUrl, String destination, String userName, String password) throws DownloadException {
System.setProperty("https.protocols", "TLSv1.2");
String fixedDownloadUrl = downloadUrl;

try {
fixedDownloadUrl = FilenameUtils.separatorsToUnix(fixedDownloadUrl);
URI downloadURI = new URI(fixedDownloadUrl);
final Path destinationPath = Path.of(destination);
if ("file".equalsIgnoreCase(downloadURI.getScheme())) {
Files.copy(Paths.get(downloadURI), destinationPath);
} else {
final HttpRequest<Buffer> request = webClient.getAbs(downloadUrl);
final CountDownLatch latch = new CountDownLatch(1);
Future<HttpResponse<Buffer>> future = request.send();
future.onComplete((r) -> latch.countDown());
latch.await(5, TimeUnit.MINUTES);
if (future.succeeded()) {
Files.write(destinationPath, future.result().body().getBytes());
} else {
throw new DownloadException("Could not download " + downloadUrl, future.cause());
}
}

} catch (URISyntaxException | IOException e) {
throw new DownloadException("Could not download " + downloadUrl, e);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
}

}
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
package io.quarkiverse.quinoa.deployment.packagemanager;

import static io.vertx.core.spi.resolver.ResolverProvider.DISABLE_DNS_RESOLVER_PROP_NAME;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.DirectoryNotEmptyException;
import java.nio.file.Path;
import java.util.Collections;
import java.util.Optional;
import java.util.Set;

import org.jboss.logging.Logger;

import com.github.eirslett.maven.plugins.frontend.lib.FrontendPluginFactory;
import com.github.eirslett.maven.plugins.frontend.lib.InstallationException;
import com.github.eirslett.maven.plugins.frontend.lib.ProxyConfig;
import com.github.eirslett.maven.plugins.frontend.lib.PackageManagerInstallFactory;

import io.quarkiverse.quinoa.deployment.config.PackageManagerInstallConfig;
import io.quarkus.deployment.util.FileUtil;
import io.quarkus.runtime.configuration.ConfigurationException;
import io.vertx.core.Vertx;
import io.vertx.core.VertxOptions;

public final class PackageManagerInstall {

Expand All @@ -33,7 +35,6 @@ private PackageManagerInstall() {

public static Installation install(PackageManagerInstallConfig config, final Path projectDir) {
Path installDir = resolveInstallDir(config, projectDir).normalize();
FrontendPluginFactory factory = new FrontendPluginFactory(null, installDir.toFile());
if (config.nodeVersion().isEmpty()) {
throw new ConfigurationException("node-version is required to install package manager",
Set.of("quarkus.quinoa.package-manager-install.node-version"));
Expand All @@ -44,29 +45,53 @@ public static Installation install(PackageManagerInstallConfig config, final Pat
}
int i = 0;
Exception thrown = null;
while (i < 5) {
try {
if (i > 0) {
LOG.warnf("An error occurred '%s' during the previous Node.js install, retrying (%s/5)",
thrown.getCause().getMessage(), i + 1);
FileUtil.deleteDirectory(installDir);
Vertx vertx = null;
try {
vertx = createVertxInstance();
PackageManagerInstallFactory factory = new PackageManagerInstallFactory(vertx, installDir);
while (i < 5) {
try {
if (i > 0) {
LOG.warnf("An error occurred '%s' during the previous Node.js install, retrying (%s/5)",
thrown.getCause().getMessage(), i + 1);
FileUtil.deleteDirectory(installDir);
}
return attemptInstall(config, installDir, factory);
} catch (InstallationException e) {
thrown = e;
i++;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return attemptInstall(config, installDir, factory);
} catch (InstallationException e) {
thrown = e;
i++;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
} finally {
vertx.close();
}

throw new RuntimeException("Error while installing NodeJS", thrown);
}

private static Vertx createVertxInstance() {
String originalValue = System.getProperty(DISABLE_DNS_RESOLVER_PROP_NAME);
Vertx vertx;
try {
System.setProperty(DISABLE_DNS_RESOLVER_PROP_NAME, "true");
vertx = Vertx.vertx(new VertxOptions());
} finally {
// Restore the original value
if (originalValue == null) {
System.clearProperty(DISABLE_DNS_RESOLVER_PROP_NAME);
} else {
System.setProperty(DISABLE_DNS_RESOLVER_PROP_NAME, originalValue);
}
}
return vertx;
}

private static Installation attemptInstall(PackageManagerInstallConfig config, Path installDir,
FrontendPluginFactory factory) throws InstallationException {
final ProxyConfig proxy = new ProxyConfig(Collections.emptyList());
PackageManagerInstallFactory factory) throws InstallationException {
try {
factory.getNodeInstaller(proxy)
factory.getNodeInstaller()
.setNodeVersion("v" + config.nodeVersion().get())
.setNodeDownloadRoot(config.nodeDownloadRoot())
.setNpmVersion(config.npmVersion())
Expand All @@ -85,7 +110,7 @@ private static Installation attemptInstall(PackageManagerInstallConfig config, P
final String npmVersion = config.npmVersion();
boolean isNpmProvided = PackageManagerInstallConfig.NPM_PROVIDED.equalsIgnoreCase(npmVersion);
if (!isNpmProvided) {
factory.getNPMInstaller(proxy)
factory.getNPMInstaller()
.setNodeVersion("v" + config.nodeVersion().get())
.setNpmVersion(npmVersion)
.setNpmDownloadRoot(config.npmDownloadRoot())
Expand All @@ -96,7 +121,7 @@ private static Installation attemptInstall(PackageManagerInstallConfig config, P
final Optional<String> yarnVersion = config.yarnVersion();
if (yarnVersion.isPresent() && isNpmProvided) {
executionPath = YARN_PATH;
factory.getYarnInstaller(proxy)
factory.getYarnInstaller()
.setYarnVersion("v" + config.yarnVersion().get())
.setYarnDownloadRoot(config.yarnDownloadRoot())
.setIsYarnBerry(true)
Expand All @@ -107,7 +132,7 @@ private static Installation attemptInstall(PackageManagerInstallConfig config, P
final Optional<String> pnpmVersion = config.pnpmVersion();
if (pnpmVersion.isPresent() && isNpmProvided && yarnVersion.isEmpty()) {
executionPath = PNPM_PATH;
factory.getPnpmInstaller(proxy)
factory.getPnpmInstaller()
.setNodeVersion("v" + config.nodeVersion().get())
.setPnpmVersion(pnpmVersion.get())
.setPnpmDownloadRoot(config.pnpmDownloadRoot())
Expand Down

0 comments on commit 50f311f

Please sign in to comment.