Skip to content

Commit d28e593

Browse files
committed
Add support for Enviornment vars in RunConfig
This is the first step towards scala-js/scala-js#4686.
1 parent 735f1c6 commit d28e593

File tree

4 files changed

+87
-6
lines changed

4 files changed

+87
-6
lines changed

Diff for: js-envs/src/main/scala/org/scalajs/jsenv/ExternalJSRun.scala

+5
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ object ExternalJSRun {
6969
validator
7070
.supportsInheritIO()
7171
.supportsOnOutputStream()
72+
.supportsAdditionalEnv()
7273
}
7374

7475
/** Configuration for a [[ExternalJSRun]]
@@ -138,6 +139,10 @@ object ExternalJSRun {
138139
for ((name, value) <- env)
139140
builder.environment().put(name, value)
140141

142+
// additionalEnv takes precedence in case of collisions.
143+
for ((name, value) <- config.additionalEnv)
144+
builder.environment().put(name, value)
145+
141146
config.logger.debug("Starting process: " + command.mkString(" "))
142147

143148
try {

Diff for: js-envs/src/main/scala/org/scalajs/jsenv/RunConfig.scala

+38-6
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,26 @@ import org.scalajs.logging._
4242
*
4343
* @param logger The logger to use in the run. A [[JSEnv]] is not required to
4444
* log anything.
45+
*
46+
* @param additionalEnv Additional environment variables for this run.
47+
*
48+
* How these are retrieved in the JS code run inside the [[JSEnv]] is
49+
* completely up to the implementation, including whether:
50+
* - they are implemented with system environment variables,
51+
* - they share the same namespace than the system environment variables.
52+
*
53+
* However, in any case, the variables in [[additionalEnv]] take precedence
54+
* over any (explicitly or implicitly) ambiant environment vars.
55+
*
56+
* This is an optional feature; but [[JSEnv]]s are required to support an
57+
* empty [[additionalEnv]].
4558
*/
4659
final class RunConfig private (
4760
val onOutputStream: Option[RunConfig.OnOutputStream],
4861
val inheritOutput: Boolean,
4962
val inheritError: Boolean,
5063
val logger: Logger,
64+
val additionalEnv: Map[String, String],
5165
/** An option that will never be supported by anything because it is not exposed.
5266
*
5367
* This is used to test that [[JSEnv]]s properly validate their configuration.
@@ -62,6 +76,7 @@ final class RunConfig private (
6276
inheritOutput = true,
6377
inheritError = true,
6478
logger = NullLogger,
79+
additionalEnv = Map.empty,
6580
eternallyUnsupportedOption = false)
6681
}
6782

@@ -77,6 +92,12 @@ final class RunConfig private (
7792
def withLogger(logger: Logger): RunConfig =
7893
copy(logger = logger)
7994

95+
def withAdditionalEnv(additionalEnv: Map[String, String]): RunConfig =
96+
copy(additionalEnv = additionalEnv)
97+
98+
def withAdditionalEnv(name: String, value: String): RunConfig =
99+
copy(additionalEnv = additionalEnv + (name -> value))
100+
80101
private[jsenv] def withEternallyUnsupportedOption(
81102
eternallyUnsupportedOption: Boolean): RunConfig =
82103
copy(eternallyUnsupportedOption = eternallyUnsupportedOption)
@@ -85,10 +106,11 @@ final class RunConfig private (
85106
inheritOutput: Boolean = inheritOutput,
86107
inheritError: Boolean = inheritError,
87108
logger: Logger = logger,
109+
additionalEnv: Map[String, String] = additionalEnv,
88110
eternallyUnsupportedOption: Boolean = eternallyUnsupportedOption
89111
): RunConfig = {
90112
new RunConfig(onOutputStream, inheritOutput, inheritError, logger,
91-
eternallyUnsupportedOption)
113+
additionalEnv, eternallyUnsupportedOption)
92114
}
93115

94116
/** Validates constraints on the config itself. */
@@ -119,9 +141,10 @@ final object RunConfig {
119141
*/
120142
final class Validator private (
121143
inheritIO: Boolean,
122-
onOutputStream: Boolean
144+
onOutputStream: Boolean,
145+
additionalEnv: Boolean
123146
) {
124-
private def this() = this(false, false)
147+
private def this() = this(false, false, false)
125148

126149
/** The caller supports [[RunConfig#inheritOutput]] and
127150
* [[RunConfig#inheritError]].
@@ -131,6 +154,9 @@ final object RunConfig {
131154
/** The caller supports [[RunConfig#onOutputStream]]. */
132155
def supportsOnOutputStream(): Validator = copy(onOutputStream = true)
133156

157+
/** The caller supports [[RunConfig#additionalEnv]]. */
158+
def supportsAdditionalEnv(): Validator = copy(additionalEnv = true)
159+
134160
/** Validates that `config` is valid and only sets supported options.
135161
*
136162
* @throws java.lang.IllegalArgumentException if there are unsupported options.
@@ -146,13 +172,19 @@ final object RunConfig {
146172
if (!onOutputStream && config.onOutputStream.isDefined)
147173
fail("onOutputStream is not supported.")
148174

175+
if (!additionalEnv && config.additionalEnv.nonEmpty)
176+
fail("additionalEnv is not supported.")
177+
149178
if (config.eternallyUnsupportedOption)
150179
fail("eternallyUnsupportedOption is not supported.")
151180
}
152181

153-
private def copy(inheritIO: Boolean = inheritIO,
154-
onOutputStream: Boolean = onOutputStream) = {
155-
new Validator(inheritIO, onOutputStream)
182+
private def copy(
183+
inheritIO: Boolean = inheritIO,
184+
onOutputStream: Boolean = onOutputStream,
185+
additionalEnv: Boolean = additionalEnv
186+
) = {
187+
new Validator(inheritIO, onOutputStream, additionalEnv)
156188
}
157189
}
158190

Diff for: js-envs/src/test/scala/org/scalajs/jsenv/ExternalJSRunTest.scala

+23
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,29 @@ class ExternalJSRunTest {
109109
Await.result(run.future, 1.second)
110110
}
111111

112+
@Test
113+
def setAdditionalEnv: Unit = {
114+
val runConfig = RunConfig()
115+
.withAdditionalEnv("EXTERNAL_JS_RUN_TEST", "witness")
116+
val config = silentConfig
117+
.withRunConfig(runConfig)
118+
val run = checkEnvRun("EXTERNAL_JS_RUN_TEST", "witness", config)
119+
120+
Await.result(run.future, 1.second)
121+
}
122+
123+
@Test
124+
def additionalEnvOverrides: Unit = {
125+
val runConfig = RunConfig()
126+
.withAdditionalEnv("EXTERNAL_JS_RUN_TEST", "override")
127+
val config = silentConfig
128+
.withEnv(Map("EXTERNAL_JS_RUN_TEST" -> "witness"))
129+
.withRunConfig(runConfig)
130+
val run = checkEnvRun("EXTERNAL_JS_RUN_TEST", "override", config)
131+
132+
Await.result(run.future, 1.second)
133+
}
134+
112135
// Confidence tests for checkEnvRun.
113136

114137
@Test

Diff for: js-envs/src/test/scala/org/scalajs/jsenv/RunConfigTest.scala

+21
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
package org.scalajs.jsenv
1414

1515
import org.junit.Test
16+
import org.junit.Assert._
1617

1718
class RunConfigTest {
1819
@Test
@@ -90,6 +91,26 @@ class RunConfigTest {
9091
.validate(cfg)
9192
}
9293

94+
@Test
95+
def supportedAdditionalEnv: Unit = {
96+
val cfg = RunConfig()
97+
.withAdditionalEnv("x", "y")
98+
RunConfig.Validator()
99+
.supportsInheritIO()
100+
.supportsAdditionalEnv()
101+
.validate(cfg)
102+
assertEquals(Map("x" -> "y"), cfg.additionalEnv)
103+
}
104+
105+
@Test(expected = classOf[IllegalArgumentException])
106+
def unsupportedAdditionalEnv: Unit = {
107+
val cfg = RunConfig()
108+
.withAdditionalEnv("x", "y")
109+
RunConfig.Validator()
110+
.supportsInheritIO()
111+
.validate(cfg)
112+
}
113+
93114
@Test(expected = classOf[IllegalArgumentException])
94115
def failValidationForTest: Unit = {
95116
val cfg = RunConfig()

0 commit comments

Comments
 (0)