Skip to content

Commit

Permalink
Read proxy config from .npmrc file (#7625)
Browse files Browse the repository at this point in the history
* Read proxy config from .npmrc file, system properties, and environment variables
  • Loading branch information
mehdi-vaadin authored Feb 20, 2020
1 parent c5e9c95 commit 6f5b5d0
Show file tree
Hide file tree
Showing 6 changed files with 389 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,11 @@ private void runWebpack() {

String nodePath;
if (requireHomeNodeExec) {
nodePath = FrontendUtils.ensureNodeExecutableInHome();
nodePath = FrontendUtils
.ensureNodeExecutableInHome(npmFolder.getAbsolutePath());
} else {
nodePath = FrontendUtils
.getNodeExecutable(npmFolder.getAbsolutePath());
.getNodeExecutable(npmFolder.getAbsolutePath());
}

List<String> command = Arrays.asList(nodePath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
Expand Down Expand Up @@ -153,7 +152,8 @@ private DevModeHandler(DeploymentConfiguration config, int runningPort,

String nodeExec = null;
if (useHomeNodeExec) {
nodeExec = FrontendUtils.ensureNodeExecutableInHome();
nodeExec = FrontendUtils
.ensureNodeExecutableInHome(npmFolder.getAbsolutePath());
} else {
nodeExec = getNodeExecutable(npmFolder.getAbsolutePath());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
Expand All @@ -38,12 +39,14 @@
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Properties;
import java.util.Scanner;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.text.WordUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -63,7 +66,6 @@
import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;

import static com.vaadin.flow.server.Constants.SERVLET_PARAMETER_STATISTICS_JSON;
import static com.vaadin.flow.server.Constants.STATISTICS_JSON_DEFAULT;
import static com.vaadin.flow.server.Constants.VAADIN_MAPPING;
Expand Down Expand Up @@ -343,6 +345,16 @@ public class FrontendUtils {
Constants.SUPPORTED_PNPM_MAJOR_VERSION,
Constants.SUPPORTED_PNPM_MINOR_VERSION);

static final String NPMRC_NOPROXY_PROPERTY_KEY = "noproxy";
static final String NPMRC_HTTPS_PROXY_PROPERTY_KEY = "https-proxy";
static final String NPMRC_PROXY_PROPERTY_KEY = "proxy";

// Proxy config properties keys (for both system properties and environment
// variables) can be either fully upper case or fully lower case
static final String SYSTEM_NOPROXY_PROPERTY_KEY = "NOPROXY";
static final String SYSTEM_HTTPS_PROXY_PROPERTY_KEY = "HTTPS_PROXY";
static final String SYSTEM_HTTP_PROXY_PROPERTY_KEY = "HTTP_PROXY";

private static FrontendToolsLocator frontendToolsLocator = new FrontendToolsLocator();

private static String operatingSystem = null;
Expand Down Expand Up @@ -397,6 +409,9 @@ public static String getNodeExecutable(String baseDir) {
/**
* Install node and npm into target directory.
*
*
* @param baseDir
* project root folder.
* @param installDirectory
* installation directory
* @param nodeVersion
Expand All @@ -407,10 +422,10 @@ public static String getNodeExecutable(String baseDir) {
* {@link NodeInstaller#setNodeDownloadRoot(URI)}.
* @return node installation path
*/
protected static String installNode(File installDirectory,
protected static String installNode(String baseDir, File installDirectory,
String nodeVersion, URI downloadRoot) {
NodeInstaller nodeInstaller = new NodeInstaller(installDirectory,
getProxies()).setNodeVersion(nodeVersion);
getProxies(baseDir)).setNodeVersion(nodeVersion);
if (downloadRoot != null) {
nodeInstaller.setNodeDownloadRoot(downloadRoot);
}
Expand All @@ -426,9 +441,118 @@ protected static String installNode(File installDirectory,
.toString();
}

private static List<ProxyConfig.Proxy> getProxies() {
// TODO: Implement proxy collection #7567
return Collections.emptyList();
/**
* Read list of configured proxies in order from system properties, .npmrc
* file in the project root folder, .npmrc file in user root folder and
* system environment variables.
*
* @param baseDir
* project root folder.
* @return list of configured proxies
*/
// Not private because of test
static List<ProxyConfig.Proxy> getProxies(String baseDir) {
File projectNpmrc = new File(baseDir, ".npmrc");
File userNpmrc = new File(FileUtils.getUserDirectory(), ".npmrc");
List<ProxyConfig.Proxy> proxyList = new ArrayList<>();

proxyList.addAll(readProxySettingsFromSystemProperties());
proxyList.addAll(
readProxySettingsFromNpmrcFile("project .npmrc", projectNpmrc));
proxyList.addAll(
readProxySettingsFromNpmrcFile("user .npmrc", userNpmrc));
proxyList.addAll(readProxySettingsFromEnvironmentVariables());

return proxyList;
}

private static List<ProxyConfig.Proxy> readProxySettingsFromNpmrcFile(
String fileDescription, File npmrc) {
if (!npmrc.exists()) {
return Collections.emptyList();
}

try (FileReader fileReader = new FileReader(npmrc)) {
List<ProxyConfig.Proxy> proxyList = new ArrayList<>(2);
Properties properties = new Properties();
properties.load(fileReader);
String noproxy = properties.getProperty(NPMRC_NOPROXY_PROPERTY_KEY);
if (noproxy != null)
noproxy = noproxy.replaceAll(",", "|");
String httpsProxyUrl = properties
.getProperty(NPMRC_HTTPS_PROXY_PROPERTY_KEY);
if (httpsProxyUrl != null) {
proxyList.add(new ProxyConfig.Proxy(
"https-proxy - " + fileDescription, httpsProxyUrl,
noproxy));
}
String proxyUrl = properties.getProperty(NPMRC_PROXY_PROPERTY_KEY);
if (proxyUrl != null) {
proxyList.add(new ProxyConfig.Proxy(
"proxy - " + fileDescription, proxyUrl, noproxy));
}
return proxyList;
} catch (IOException e) {
throw new UncheckedIOException(e);
}
}

private static List<ProxyConfig.Proxy> readProxySettingsFromSystemProperties() {
List<ProxyConfig.Proxy> proxyList = new ArrayList<>(2);

String noproxy = ObjectUtils.firstNonNull(
System.getProperty(SYSTEM_NOPROXY_PROPERTY_KEY),
System.getProperty(SYSTEM_NOPROXY_PROPERTY_KEY.toLowerCase()));
if (noproxy != null)
noproxy = noproxy.replaceAll(",", "|");

String httpsProxyUrl = ObjectUtils.firstNonNull(
System.getProperty(SYSTEM_HTTPS_PROXY_PROPERTY_KEY),
System.getProperty(
SYSTEM_HTTPS_PROXY_PROPERTY_KEY.toLowerCase()));
if (httpsProxyUrl != null) {
proxyList.add(new ProxyConfig.Proxy("https-proxy - system",
httpsProxyUrl, noproxy));
}

String proxyUrl = ObjectUtils.firstNonNull(
System.getProperty(SYSTEM_HTTP_PROXY_PROPERTY_KEY),
System.getProperty(
SYSTEM_HTTP_PROXY_PROPERTY_KEY.toLowerCase()));
if (proxyUrl != null) {
proxyList.add(
new ProxyConfig.Proxy("proxy - system", proxyUrl, noproxy));
}

return proxyList;
}

private static List<ProxyConfig.Proxy> readProxySettingsFromEnvironmentVariables() {
List<ProxyConfig.Proxy> proxyList = new ArrayList<>(2);

String noproxy = ObjectUtils.firstNonNull(
System.getenv(SYSTEM_NOPROXY_PROPERTY_KEY),
System.getenv(SYSTEM_NOPROXY_PROPERTY_KEY.toLowerCase()));
if (noproxy != null)
noproxy = noproxy.replaceAll(",", "|");

String httpsProxyUrl = ObjectUtils.firstNonNull(
System.getenv(SYSTEM_HTTPS_PROXY_PROPERTY_KEY),
System.getenv(SYSTEM_HTTPS_PROXY_PROPERTY_KEY.toLowerCase()));
if (httpsProxyUrl != null) {
proxyList.add(new ProxyConfig.Proxy("https-proxy - env",
httpsProxyUrl, noproxy));
}

String proxyUrl = ObjectUtils.firstNonNull(
System.getenv(SYSTEM_HTTP_PROXY_PROPERTY_KEY),
System.getenv(SYSTEM_HTTP_PROXY_PROPERTY_KEY.toLowerCase()));
if (proxyUrl != null) {
proxyList.add(
new ProxyConfig.Proxy("proxy - env", proxyUrl, noproxy));
}

return proxyList;
}

/**
Expand All @@ -440,15 +564,17 @@ private static List<ProxyConfig.Proxy> getProxies() {
* in a search algorithm: {@link #getNodeExecutable(String)} first searches
* executable in the provided directory and fallback to the globally
* installed if it's not found there. The
* {@link #ensureNodeExecutableInHome()} doesn't search for globally
* {@link #ensureNodeExecutableInHome(String)} doesn't search for globally
* installed executable. It tries to find it in the vaadin home directory
* and if it's not found it downloads and installs it there.
*
* @see #getNodeExecutable(String)
*
* @param baseDir
* project root folder.
* @return the full path to the executable
*/
public static String ensureNodeExecutableInHome() {
public static String ensureNodeExecutableInHome(String baseDir) {
Pair<String, String> nodeCommands = getNodeCommands();
try {
File home = getVaadinHomeDirectory();
Expand All @@ -461,7 +587,7 @@ public static String ensureNodeExecutableInHome() {
}
return file.getAbsolutePath();
} else {
return installNode(getVaadinHomeDirectory(),
return installNode(baseDir, getVaadinHomeDirectory(),
DEFAULT_NODE_VERSION, null);
}
} catch (FileNotFoundException exception) {
Expand Down Expand Up @@ -559,7 +685,7 @@ private static File getExecutable(String baseDir, String cmd,
.orElse(null));
}
if (file == null && installNode) {
return new File(installNode(getVaadinHomeDirectory(),
return new File(installNode(baseDir, getVaadinHomeDirectory(),
DEFAULT_NODE_VERSION, null));
}
} catch (FileNotFoundException exception) {
Expand All @@ -570,7 +696,7 @@ private static File getExecutable(String baseDir, String cmd,
// There are IOException coming from process fork
}
if (file == null) {
throw new IllegalStateException(String.format(NODE_NOT_FOUND));
throw new IllegalStateException(format(NODE_NOT_FOUND));
}
return file;
}
Expand Down Expand Up @@ -748,8 +874,8 @@ public static String getStatsHash(VaadinService service)
.prepareConnection("/stats.hash", "GET");
if (statsConnection
.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new WebpackConnectionException(String.format(
NO_CONNECTION, "getting the stats content hash."));
throw new WebpackConnectionException(format(NO_CONNECTION,
"getting the stats content hash."));
}
return streamToString(statsConnection.getInputStream())
.replaceAll("\"", "");
Expand All @@ -764,7 +890,7 @@ private static InputStream getStatsFromWebpack() throws IOException {
.prepareConnection("/stats.json", "GET");
if (statsConnection.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new WebpackConnectionException(
String.format(NO_CONNECTION, "downloading stats.json"));
format(NO_CONNECTION, "downloading stats.json"));
}
return statsConnection.getInputStream();
}
Expand Down Expand Up @@ -870,8 +996,8 @@ public static String getStatsAssetsByChunkName(VaadinService service)
.prepareConnection("/assetsByChunkName", "GET");
if (assetsConnection
.getResponseCode() != HttpURLConnection.HTTP_OK) {
throw new WebpackConnectionException(String.format(
NO_CONNECTION, "getting assets by chunk name."));
throw new WebpackConnectionException(
format(NO_CONNECTION, "getting assets by chunk name."));
}
return streamToString(assetsConnection.getInputStream());
}
Expand Down Expand Up @@ -1045,7 +1171,7 @@ private static boolean isPnpmTooOldOrAbsent(String baseDir) {
if (isVersionAtLeast(pnpmVersion, SUPPORTED_PNPM_VERSION)) {
return false;
} else {
getLogger().warn(String.format(
getLogger().warn(format(
"installed pnpm ('%s', version %s) is too old, installing supported version locally",
String.join(" ", pnpmCommand),
pnpmVersion.getFullVersion()));
Expand Down Expand Up @@ -1115,13 +1241,13 @@ private static void installPnpm(String baseDir,

private static String buildTooOldString(String tool, String version,
int supportedMajor, int supportedMinor) {
return String.format(TOO_OLD, tool, version, supportedMajor,
supportedMinor, PARAM_IGNORE_VERSION_CHECKS);
return format(TOO_OLD, tool, version, supportedMajor, supportedMinor,
PARAM_IGNORE_VERSION_CHECKS);
}

private static String buildShouldWorkString(String tool, String version,
int supportedMajor, int supportedMinor) {
return String.format(SHOULD_WORK, tool, version, supportedMajor,
return format(SHOULD_WORK, tool, version, supportedMajor,
supportedMinor, PARAM_IGNORE_VERSION_CHECKS);
}

Expand All @@ -1131,8 +1257,8 @@ private static String buildBadVersionString(String tool, String version,
for (String instruction : extraUpdateInstructions) {
extraInstructions.append("%n - or ").append(instruction);
}
return String.format(BAD_VERSION, tool, version,
extraInstructions.toString(), PARAM_IGNORE_VERSION_CHECKS);
return format(BAD_VERSION, tool, version, extraInstructions.toString(),
PARAM_IGNORE_VERSION_CHECKS);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ private void runNpmInstall() throws ExecutionFailedException {

try {
if (requireHomeNodeExec) {
FrontendUtils.ensureNodeExecutableInHome();
FrontendUtils.ensureNodeExecutableInHome(baseDir);
}
executable = enablePnpm ? FrontendUtils.getPnpmExecutable(baseDir)
: FrontendUtils.getNpmExecutable(baseDir);
Expand Down
Loading

0 comments on commit 6f5b5d0

Please sign in to comment.