From c3d33a1a0bdb5ed32eff916172c49d6d3e961243 Mon Sep 17 00:00:00 2001 From: Guillaume Nodet Date: Wed, 10 Feb 2021 21:36:02 +0100 Subject: [PATCH] Make sure the environment is properly updated, fixes #352 --- .../org/apache/maven/cli/DaemonMavenCli.java | 50 ++++++++++++-- .../mvndaemon/mvnd/it/EnvironmentTest.java | 69 +++++++++++++++++++ .../projects/environment/.mvn/maven.config | 3 + .../test/projects/environment/prj1/pom.xml | 27 ++++++++ .../test/projects/environment/prj2/pom.xml | 27 ++++++++ pom.xml | 2 +- 6 files changed, 173 insertions(+), 5 deletions(-) create mode 100644 integration-tests/src/test/java/org/mvndaemon/mvnd/it/EnvironmentTest.java create mode 100644 integration-tests/src/test/projects/environment/.mvn/maven.config create mode 100644 integration-tests/src/test/projects/environment/prj1/pom.xml create mode 100644 integration-tests/src/test/projects/environment/prj2/pom.xml diff --git a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java index 8f643fc2..27c31337 100644 --- a/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java +++ b/daemon/src/main/java/org/apache/maven/cli/DaemonMavenCli.java @@ -23,6 +23,7 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.PrintStream; +import java.lang.reflect.Field; import java.nio.file.Files; import java.util.ArrayList; import java.util.Collections; @@ -94,6 +95,7 @@ import org.codehaus.plexus.classworlds.realm.ClassRealm; import org.codehaus.plexus.component.repository.exception.ComponentLookupException; import org.codehaus.plexus.util.StringUtils; import org.eclipse.aether.transfer.TransferListener; +import org.fusesource.jansi.internal.CLibrary; import org.mvndaemon.mvnd.cache.invalidating.InvalidatingExtensionRealmCache; import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginArtifactsCache; import org.mvndaemon.mvnd.cache.invalidating.InvalidatingPluginRealmCache; @@ -208,6 +210,7 @@ public class DaemonMavenCli { Properties props = (Properties) System.getProperties().clone(); try { initialize(cliRequest); + environment(cliRequest.workingDirectory, clientEnv); cli(cliRequest); properties(cliRequest); help(cliRequest); @@ -219,7 +222,6 @@ public class DaemonMavenCli { populateRequest(cliRequest); encryption(cliRequest); repository(cliRequest); - environment(clientEnv); return execute(cliRequest); } catch (ExitException e) { return e.exitCode; @@ -650,17 +652,26 @@ public class DaemonMavenCli { } } - private void environment(Map clientEnv) { + private void environment(String workingDir, Map clientEnv) { Map requested = new TreeMap<>(clientEnv); Map actual = new TreeMap<>(System.getenv()); + requested.put("PWD", workingDir); List diffs = Stream.concat(requested.keySet().stream(), actual.keySet().stream()) .sorted() .distinct() .filter(s -> !s.startsWith("JAVA_MAIN_CLASS_")) .filter(key -> !Objects.equals(requested.get(key), actual.get(key))) .collect(Collectors.toList()); - if (!diffs.isEmpty()) { - slf4jLogger.warn("Environment mismatch !"); + try { + for (String key : diffs) { + String vr = requested.get(key); + CLibrary.setenv(key, vr); + } + setEnv(clientEnv); + CLibrary.chdir(workingDir); + System.setProperty("user.dir", workingDir); + } catch (Exception e) { + slf4jLogger.warn("Environment mismatch ! Could not set the environment (" + e + ")"); slf4jLogger.warn("A few environment mismatches have been detected between the client and the daemon."); diffs.forEach(key -> { String vr = requested.get(key); @@ -672,6 +683,37 @@ public class DaemonMavenCli { } } + @SuppressWarnings("unchecked") + protected static void setEnv(Map newenv) throws Exception { + try { + Class processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment"); + Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment"); + theEnvironmentField.setAccessible(true); + Map env = (Map) theEnvironmentField.get(null); + env.clear(); + env.putAll(newenv); + Field theCaseInsensitiveEnvironmentField = processEnvironmentClass + .getDeclaredField("theCaseInsensitiveEnvironment"); + theCaseInsensitiveEnvironmentField.setAccessible(true); + Map cienv = (Map) theCaseInsensitiveEnvironmentField.get(null); + cienv.clear(); + cienv.putAll(newenv); + } catch (NoSuchFieldException e) { + Class[] classes = Collections.class.getDeclaredClasses(); + Map env = System.getenv(); + for (Class cl : classes) { + if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) { + Field field = cl.getDeclaredField("m"); + field.setAccessible(true); + Object obj = field.get(env); + Map map = (Map) obj; + map.clear(); + map.putAll(newenv); + } + } + } + } + private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulationException { commands(cliRequest); diff --git a/integration-tests/src/test/java/org/mvndaemon/mvnd/it/EnvironmentTest.java b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/EnvironmentTest.java new file mode 100644 index 00000000..e7bed3d5 --- /dev/null +++ b/integration-tests/src/test/java/org/mvndaemon/mvnd/it/EnvironmentTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2021 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.mvndaemon.mvnd.it; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.Arrays; +import javax.inject.Inject; +import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.Test; +import org.mvndaemon.mvnd.assertj.TestClientOutput; +import org.mvndaemon.mvnd.client.Client; +import org.mvndaemon.mvnd.junit.ClientFactory; +import org.mvndaemon.mvnd.junit.MvndTest; +import org.mvndaemon.mvnd.junit.TestParameters; +import org.mvndaemon.mvnd.junit.TestRegistry; + +import static org.junit.jupiter.api.Assertions.assertTrue; + +@MvndTest(projectDir = "src/test/projects/environment") +public class EnvironmentTest { + + @Inject + TestRegistry registry; + + @Inject + ClientFactory clientFactory; + + @Inject + TestParameters parameters; + + @Test + void cleanInstall() throws IOException, InterruptedException { + assertDaemonRegistrySize(0); + /* Install the dependencies */ + for (String artifactDir : Arrays.asList("project/prj1", "project/prj2")) { + Path dir = parameters.getTestDir().resolve(artifactDir); + final Client cl = clientFactory.newClient(parameters.cd(dir)); + final TestClientOutput output = new TestClientOutput(); + cl.execute(output, "org.apache.maven.plugins:maven-help-plugin:3.2.0:evaluate", + "-Dexpression=user.dir", "-e").assertSuccess(); + assertDaemonRegistrySize(1); + String pathStr = dir.toAbsolutePath().toString(); + assertTrue(output.getMessages().stream() + .anyMatch(m -> m.toString().contains(pathStr)), "Output should contain " + pathStr); + } + assertDaemonRegistrySize(1); + } + + private void assertDaemonRegistrySize(int size) { + Assertions.assertThat(registry.getAll().size()) + .as("Daemon registry size should be " + size) + .isEqualTo(size); + } + +} diff --git a/integration-tests/src/test/projects/environment/.mvn/maven.config b/integration-tests/src/test/projects/environment/.mvn/maven.config new file mode 100644 index 00000000..4230c241 --- /dev/null +++ b/integration-tests/src/test/projects/environment/.mvn/maven.config @@ -0,0 +1,3 @@ +-Dmaven.wagon.httpconnectionManager.ttlSeconds=120 +-Dmaven.wagon.http.retryHandler.requestSentEnabled=true +-Dmaven.wagon.http.retryHandler.count=10 diff --git a/integration-tests/src/test/projects/environment/prj1/pom.xml b/integration-tests/src/test/projects/environment/prj1/pom.xml new file mode 100644 index 00000000..92859c14 --- /dev/null +++ b/integration-tests/src/test/projects/environment/prj1/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + org.mvndaemon.mvnd.test.environment + environment-prj1 + 0.0.1-SNAPSHOT + pom + + \ No newline at end of file diff --git a/integration-tests/src/test/projects/environment/prj2/pom.xml b/integration-tests/src/test/projects/environment/prj2/pom.xml new file mode 100644 index 00000000..4506e385 --- /dev/null +++ b/integration-tests/src/test/projects/environment/prj2/pom.xml @@ -0,0 +1,27 @@ + + + + 4.0.0 + org.mvndaemon.mvnd.test.environment + environment-prj2 + 0.0.1-SNAPSHOT + pom + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index a8ef0d01..6e0d584a 100644 --- a/pom.xml +++ b/pom.xml @@ -40,7 +40,7 @@ 20.3.0 3.0.7 1.0 - 2.1.1 + 2.3.1 3.18.0 5.6.0 1.2.3