From 9fb0bcb67086f7495797eeb79588653dbf2303d6 Mon Sep 17 00:00:00 2001 From: Xieshen Date: Wed, 13 Sep 2023 00:39:34 -0400 Subject: [PATCH] feat: set environment variables when executing commands --- .../exhort/providers/JavaMavenProvider.java | 19 ++++++++---- .../providers/JavaScriptNpmProvider.java | 29 +++++++++++++++---- .../com/redhat/exhort/tools/Operations.java | 24 +++++++++++++-- 3 files changed, 59 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/redhat/exhort/providers/JavaMavenProvider.java b/src/main/java/com/redhat/exhort/providers/JavaMavenProvider.java index 0421eecc..2cac1915 100644 --- a/src/main/java/com/redhat/exhort/providers/JavaMavenProvider.java +++ b/src/main/java/com/redhat/exhort/providers/JavaMavenProvider.java @@ -19,9 +19,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; import java.util.stream.Collectors; import javax.xml.stream.XMLInputFactory; @@ -61,8 +59,9 @@ public Content provideStack(final Path manifestPath) throws IOException { var mvn = Operations.getCustomPathOrElse("mvn"); // clean command used to clean build target var mvnCleanCmd = new String[]{mvn, "-q", "clean", "-f", manifestPath.toString()}; + var mvnEnvs = getMvnExecEnvs(); // execute the clean command - Operations.runProcess(mvnCleanCmd); + Operations.runProcess(mvnCleanCmd, mvnEnvs); // create a temp file for storing the dependency tree in var tmpFile = Files.createTempFile("exhort_dot_graph_", null); // the tree command will build the project and create the dependency tree in the temp file @@ -84,7 +83,7 @@ public Content provideStack(final Path manifestPath) throws IOException { .map(PackageURL::getCoordinates) .collect(Collectors.toList()); // execute the tree command - Operations.runProcess(mvnTreeCmd.toArray(String[]::new)); + Operations.runProcess(mvnTreeCmd.toArray(String[]::new), mvnEnvs); var sbom = buildSbomFromDot(tmpFile); // build and return content for constructing request to the backend return new Content(sbom.filterIgnoredDeps(ignored).getAsJsonString().getBytes(), Api.CYCLONEDX_MEDIA_TYPE); @@ -152,7 +151,7 @@ private Content generateSbomFromEffectivePom(Path originPom) throws IOException "-f", originPom.toString() }; // execute the effective pom command - Operations.runProcess(mvnEffPomCmd); + Operations.runProcess(mvnEffPomCmd, getMvnExecEnvs()); // if we have dependencies marked as ignored grab ignored dependencies from the original pom // the effective-pom goal doesn't carry comments List dependencies = getDependencies(originPom); @@ -301,6 +300,14 @@ private List getDependencies(final Path manifestPath) thro return deps; } + private Map getMvnExecEnvs() { + var javaHome = System.getProperty("JAVA_HOME"); + if (javaHome != null && !javaHome.isBlank()) { + return Collections.singletonMap("JAVA_HOME", javaHome); + } + return null; + } + // NOTE if we want to include "scope" tags in ignore, // add property here and a case in the start-element-switch in the getIgnored method /** Aggregator class for aggregating Dependency data over stream iterations, **/ diff --git a/src/main/java/com/redhat/exhort/providers/JavaScriptNpmProvider.java b/src/main/java/com/redhat/exhort/providers/JavaScriptNpmProvider.java index a22fb16f..5bcd34b8 100644 --- a/src/main/java/com/redhat/exhort/providers/JavaScriptNpmProvider.java +++ b/src/main/java/com/redhat/exhort/providers/JavaScriptNpmProvider.java @@ -15,14 +15,13 @@ */ package com.redhat.exhort.providers; +import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; +import java.util.*; import java.util.Map.Entry; import com.fasterxml.jackson.core.JsonProcessingException; @@ -127,19 +126,26 @@ private Sbom getDependencySbom(Path manifestPath, boolean includeTransitive) thr private JsonNode buildNpmDependencyTree(Path manifestPath, boolean includeTransitive) throws JsonMappingException, JsonProcessingException { var npm = Operations.getCustomPathOrElse("npm"); + var npmEnvs = getNpmExecEnv(); // clean command used to clean build target Path packageLockJson = Path.of(manifestPath.getParent().toString(), "package-lock.json"); if (!packageLockJson.toFile().exists()) { var createPackageLock = new String[] { npm, "i", "--package-lock-only", "--prefix", manifestPath.getParent().toString() }; // execute the clean command - Operations.runProcess(createPackageLock); + Operations.runProcess(createPackageLock, npmEnvs); } var npmAllDeps = new String[] { npm, "ls", includeTransitive ? "--all" : "", "--omit=dev", "--package-lock-only", "--json", "--prefix", manifestPath.getParent().toString() }; // execute the clean command - String npmOutput = Operations.runProcessGetOutput(null,npmAllDeps); + String npmOutput; + if (npmEnvs != null) { + npmOutput = Operations.runProcessGetOutput(null, npmAllDeps, + npmEnvs.entrySet().stream().map(e -> e.getKey() + "=" + e.getValue()).toArray(String[]::new)); + } else { + npmOutput = Operations.runProcessGetOutput(null, npmAllDeps); + } if(!includeTransitive) { try { @@ -176,4 +182,17 @@ private List getIgnoredDeps(Path manifestPath) throws IOException { } return ignored; } + + private Map getNpmExecEnv() { + String nodeHome = System.getProperty("NODE_HOME"); + if (nodeHome != null && !nodeHome.isBlank()) { + String path = System.getenv("PATH"); + if (path != null) { + return Collections.singletonMap("PATH", path + File.pathSeparator + nodeHome); + } else { + return Collections.singletonMap("PATH", nodeHome); + } + } + return null; + } } diff --git a/src/main/java/com/redhat/exhort/tools/Operations.java b/src/main/java/com/redhat/exhort/tools/Operations.java index a7112de4..2acbd831 100644 --- a/src/main/java/com/redhat/exhort/tools/Operations.java +++ b/src/main/java/com/redhat/exhort/tools/Operations.java @@ -20,6 +20,7 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.nio.file.Path; +import java.util.Map; import java.util.Objects; /** Utility class used for executing process on the operating system. **/ @@ -55,8 +56,15 @@ public static String getCustomPathOrElse(String defaultExecutable) { * @param cmdList list of command parts */ public static void runProcess(final String... cmdList) { + runProcess(cmdList, null); + } + + public static void runProcess(final String[] cmdList, final Map envMap) { var processBuilder = new ProcessBuilder(); processBuilder.command(cmdList); + if (envMap != null) { + processBuilder.environment().putAll(envMap); + } // create a process builder or throw a runtime exception Process process = null; @@ -100,16 +108,28 @@ public static void runProcess(final String... cmdList) { } public static String runProcessGetOutput(Path dir, final String... cmdList) { + return runProcessGetOutput(dir, cmdList, null); + } + + public static String runProcessGetOutput(Path dir, final String[] cmdList, String[] envList) { StringBuilder sb = new StringBuilder(); try { Process process; InputStream inputStream; if(dir == null) { - process = Runtime.getRuntime().exec(String.join(" ", cmdList)); + if (envList != null) { + process = Runtime.getRuntime().exec(String.join(" ", cmdList), envList); + } else { + process = Runtime.getRuntime().exec(String.join(" ", cmdList)); + } } else { - process = Runtime.getRuntime().exec(String.join(" ", cmdList),null,dir.toFile()); + if (envList != null) { + process = Runtime.getRuntime().exec(String.join(" ", cmdList), envList, dir.toFile()); + } else { + process = Runtime.getRuntime().exec(String.join(" ", cmdList), null, dir.toFile()); + } }