Merge pull request #12800 from nosan:gh-11065

* pr/12800:
  Polish "Add support for environment variables"
  Add support for environment variables
pull/12955/merge
Stephane Nicoll 7 years ago
commit 9ed169a70b

@ -20,6 +20,8 @@ import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
/**
* Utility used to run a process.
@ -28,6 +30,7 @@ import java.util.Collection;
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
* @author Dmytro Nosan
* @since 1.1.0
*/
public class RunProcess {
@ -63,14 +66,15 @@ public class RunProcess {
}
public int run(boolean waitForProcess, String... args) throws IOException {
return run(waitForProcess, Arrays.asList(args));
return run(waitForProcess, Arrays.asList(args), Collections.emptyMap());
}
protected int run(boolean waitForProcess, Collection<String> args)
throws IOException {
public int run(boolean waitForProcess, Collection<String> args,
Map<String, String> environmentVariables) throws IOException {
ProcessBuilder builder = new ProcessBuilder(this.command);
builder.directory(this.workingDirectory);
builder.command().addAll(args);
builder.environment().putAll(environmentVariables);
builder.redirectErrorStream(true);
builder.inheritIO();
try {

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.boot.maven.it</groupId>
<artifactId>run-envargs</artifactId>
<version>0.0.1.BUILD-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>@java.version@</maven.compiler.source>
<maven.compiler.target>@java.version@</maven.compiler.target>
</properties>
<build>
<plugins>
<plugin>
<groupId>@project.groupId@</groupId>
<artifactId>@project.artifactId@</artifactId>
<version>@project.version@</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<environmentVariables>
<ENV1>5000</ENV1>
<ENV2>Some Text</ENV2>
<ENV3/>
<ENV4></ENV4>
</environmentVariables>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,38 @@
/*
* Copyright 2012-2018 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.test;
public class SampleApplication {
public static void main(String[] args) {
assertEnvValue("ENV1", "5000");
assertEnvValue("ENV2", "Some Text");
assertEnvValue("ENV3", "");
assertEnvValue("ENV4", "");
System.out.println("I haz been run");
}
private static void assertEnvValue(String envKey, String expectedValue) {
String actual = System.getenv(envKey);
if (!expectedValue.equals(actual)) {
throw new IllegalStateException("env property [" + envKey + "] mismatch "
+ "(got [" + actual + "], expected [" + expectedValue + "]");
}
}
}

@ -0,0 +1,3 @@
def file = new File(basedir, "build.log")
return file.text.contains("I haz been run")

@ -48,6 +48,7 @@ import org.springframework.boot.loader.tools.MainClassFinder;
* @author Stephane Nicoll
* @author David Liu
* @author Daniel Young
* @author Dmytro Nosan
* @see RunMojo
* @see StartMojo
*/
@ -115,6 +116,15 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
@Parameter
private Map<String, String> systemPropertyVariables;
/**
* List of Environment variables that should be associated with the forked process
* used to run the application. NOTE: the use of Environment variables means that
* processes will be started by forking a new JVM.
* @since 2.1
*/
@Parameter
private Map<String, String> environmentVariables;
/**
* Arguments that should be passed to the application. On command line use commas to
* separate multiple arguments.
@ -203,7 +213,7 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
* @see #logDisabledFork()
*/
protected boolean enableForkByDefault() {
return hasAgent() || hasJvmArgs() || hasWorkingDirectorySet();
return hasAgent() || hasJvmArgs() || hasEnvVariables() || hasWorkingDirectorySet();
}
private boolean hasAgent() {
@ -216,6 +226,10 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
&& !this.systemPropertyVariables.isEmpty());
}
private boolean hasEnvVariables() {
return (this.environmentVariables != null && !this.environmentVariables.isEmpty());
}
private boolean hasWorkingDirectorySet() {
return this.workingDirectory != null;
}
@ -262,17 +276,19 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
addClasspath(args);
args.add(startClassName);
addArgs(args);
runWithForkedJvm(this.workingDirectory, args);
runWithForkedJvm(this.workingDirectory, args, determineEnvironmentVariables());
}
/**
* Run with a forked VM, using the specified command line arguments.
* @param workingDirectory the working directory of the forked JVM
* @param args the arguments (JVM arguments and application arguments)
* @param environmentVariables the environment variables
* @throws MojoExecutionException in case of MOJO execution errors
* @throws MojoFailureException in case of MOJO failures
*/
protected abstract void runWithForkedJvm(File workingDirectory, List<String> args)
protected abstract void runWithForkedJvm(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException, MojoFailureException;
/**
@ -295,12 +311,26 @@ public abstract class AbstractRunMojo extends AbstractDependencyFilterMojo {
return runArguments;
}
/**
* Resolve the environment variables to use.
* @return a {@link EnvVariables} defining the environment variables
*/
protected EnvVariables resolveEnvVariables() {
return new EnvVariables(this.environmentVariables);
}
private void addArgs(List<String> args) {
RunArguments applicationArguments = resolveApplicationArguments();
Collections.addAll(args, applicationArguments.asArray());
logArguments("Application argument(s): ", this.arguments);
}
private Map<String, String> determineEnvironmentVariables() {
EnvVariables envVariables = resolveEnvVariables();
logArguments("Environment variable(s): ", envVariables.asArray());
return envVariables.asMap();
}
/**
* Resolve the JVM arguments to use.
* @return a {@link RunArguments} defining the JVM arguments

@ -0,0 +1,67 @@
/*
* Copyright 2012-2018 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.springframework.boot.maven;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Utility class for working with Env variables.
*
* @author Dmytro Nosan
*/
class EnvVariables {
private final Map<String, String> variables;
EnvVariables(Map<String, String> variables) {
this.variables = parseEnvVariables(variables);
}
private static Map<String, String> parseEnvVariables(Map<String, String> args) {
if (args == null || args.isEmpty()) {
return Collections.emptyMap();
}
Map<String, String> result = new LinkedHashMap<>();
for (Map.Entry<String, String> e : args.entrySet()) {
if (e.getKey() != null) {
result.put(e.getKey(), getValue(e.getValue()));
}
}
return result;
}
private static String getValue(String value) {
return (value != null ? value : "");
}
public Map<String, String> asMap() {
return Collections.unmodifiableMap(this.variables);
}
public String[] asArray() {
List<String> args = new ArrayList<>(this.variables.size());
for (Map.Entry<String, String> arg : this.variables.entrySet()) {
args.add(arg.getKey() + "=" + arg.getValue());
}
return args.toArray(new String[0]);
}
}

@ -20,6 +20,7 @@ import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.List;
import java.util.Map;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Execute;
@ -34,6 +35,7 @@ import org.springframework.boot.loader.tools.RunProcess;
* Run an executable archive application.
*
* @author Phillip Webb
* @author Dmytro Nosan
* @author Stephane Nicoll
* @author Andy Wilkinson
*/
@ -64,14 +66,15 @@ public class RunMojo extends AbstractRunMojo {
}
@Override
protected void runWithForkedJvm(File workingDirectory, List<String> args)
protected void runWithForkedJvm(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory,
new JavaExecutable().toString());
Runtime.getRuntime()
.addShutdownHook(new Thread(new RunProcessKiller(runProcess)));
int exitCode = runProcess.run(true, args.toArray(new String[0]));
int exitCode = runProcess.run(true, args, environmentVariables);
if (exitCode == 0 || exitCode == EXIT_CODE_SIGINT) {
return;
}

@ -23,6 +23,7 @@ import java.net.ConnectException;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import javax.management.MBeanServerConnection;
@ -88,9 +89,10 @@ public class StartMojo extends AbstractRunMojo {
private final Object lock = new Object();
@Override
protected void runWithForkedJvm(File workingDirectory, List<String> args)
protected void runWithForkedJvm(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException, MojoFailureException {
RunProcess runProcess = runProcess(workingDirectory, args);
RunProcess runProcess = runProcess(workingDirectory, args, environmentVariables);
try {
waitForSpringApplication();
}
@ -100,12 +102,13 @@ public class StartMojo extends AbstractRunMojo {
}
}
private RunProcess runProcess(File workingDirectory, List<String> args)
private RunProcess runProcess(File workingDirectory, List<String> args,
Map<String, String> environmentVariables)
throws MojoExecutionException {
try {
RunProcess runProcess = new RunProcess(workingDirectory,
new JavaExecutable().toString());
runProcess.run(false, args.toArray(new String[0]));
runProcess.run(false, args, environmentVariables);
return runProcess;
}
catch (Exception ex) {

@ -0,0 +1,50 @@
-----
Using environment variables
-----
Dmytro Nosan
-----
2018-04-08
-----
Environment variables can be specified using the <<<environmentVariables>>> attribute.
The following sets the 'ENV1', 'ENV2', 'ENV3', 'ENV4' env variables:
---
<project>
...
<build>
...
<plugins>
...
<plugin>
<groupId>${project.groupId}</groupId>
<artifactId>${project.artifactId}</artifactId>
<version>${project.version}</version>
<configuration>
<environmentVariables>
<ENV1>5000</ENV1>
<ENV2>Some Text</ENV2>
<ENV3/>
<ENV4></ENV4>
</environmentVariables>
</configuration>
...
</plugin>
...
</plugins>
...
</build>
...
</project>
---
If the value is empty or not defined (i.e. <<<<MY_ENV/>>>>), the env variable is set
with an empty String as the value.
Any String typed Maven variable can be passed as system properties. Any attempt to pass
any other Maven variable type (e.g. a <<<List>>> or a <<<URL>>> variable) will cause the
variable expression to be passed literally (unevaluated).
Environment variables defined this way take precedence over existing values.

@ -54,6 +54,8 @@ Spring Boot Maven Plugin
* {{{./examples/run-system-properties.html}Using system properties}}
* {{{./examples/run-env-variables.html}Using environment variables}}
* {{{./examples/it-random-port.html}Random port for integration tests}}
* {{{./examples/it-skip.html}Skip integration tests}}

@ -135,15 +135,17 @@ mvn spring-boot:run
By default the application is executed directly from the Maven JVM. If you need to run
in a forked process you can use the 'fork' option. Forking will also occur if the
'jvmArguments', 'systemPropertyVariables' or 'agent' options are specified, or if
devtools is present.
'jvmArguments', 'systemPropertyVariables', 'environmentVariables' or 'agent' options
are specified, or if devtools is present.
If you need to specify some JVM arguments (i.e. for debugging purposes), you can use
the <<<jvmArguments>>> parameter, see {{{./examples/run-debug.html}Debug the application}}
for more details. There is also explicit support
{{{./examples/run-system-properties.html}for system properties}}. As a convenience, the
profiles to enable are handled by a specific property (<<<profiles>>>), see
{{{./examples/run-profiles.html}Specify active profiles}}.
for more details. There is also explicit support for
{{{./examples/run-system-properties.html}system properties}} and
{{{./examples/run-env-variables.html}environment variables}}.
As a convenience, the profiles to enable are handled by a specific property (
<<<profiles>>>), see {{{./examples/run-profiles.html}Specify active profiles}}.
Spring Boot 1.3 has introduced <<<devtools>>>, a module to improve the development-time
experience when working on Spring Boot applications. To enable it, just add the following

@ -12,6 +12,7 @@
<item name="Exclude a dependency" href="examples/exclude-dependency.html"/>
<item name="Debug the application" href="examples/run-debug.html"/>
<item name="Using system properties" href="examples/run-system-properties.html"/>
<item name="Using environment variable" href="examples/run-env-variables.html"/>
<item name="Random port for integration tests" href="examples/it-random-port.html"/>
<item name="Skip integration tests" href="examples/it-skip.html"/>
<item name="Specify active profiles" href="examples/run-profiles.html"/>

@ -0,0 +1,62 @@
/*
* Copyright 2012-2018 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.springframework.boot.maven;
import java.util.LinkedHashMap;
import java.util.Map;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.entry;
/**
* Tests for {@link EnvVariables}.
*
* @author Dmytro Nosan
*/
public class EnvVariablesTests {
@Test
public void asNull() {
Map<String, String> args = new EnvVariables(null).asMap();
assertThat(args).isEmpty();
}
@Test
public void asArray() {
assertThat(new EnvVariables(getTestArgs()).asArray())
.contains("key=My Value", "key1= tt ", "key2= ", "key3=");
}
@Test
public void asMap() {
assertThat(new EnvVariables(getTestArgs()).asMap()).containsExactly(
entry("key", "My Value"), entry("key1", " tt "), entry("key2", " "),
entry("key3", ""));
}
private Map<String, String> getTestArgs() {
Map<String, String> args = new LinkedHashMap<>();
args.put("key", "My Value");
args.put("key1", " tt ");
args.put("key2", " ");
args.put("key3", null);
return args;
}
}
Loading…
Cancel
Save