Skip to content

Commit 7224671

Browse files
staticfloatKristofferC
authored andcommitted
addenv(), by default, should inherit from ENV (#39100)
The spirit of `addenv()` is to be non-destructive, however because a `Cmd` object with an `env` member that is set to `nothing` (the default) inherts from the current environment when it is run. This means that the following, rather surprising behavior holds true on current master: ``` julia> ENV["FOO"] = "foo" run(`/bin/bash -c "echo \$FOO \$BAR"`) run(addenv(`/bin/bash -c "echo \$FOO \$BAR"`, "BAR" => "bar")) foo bar ``` This PR adds an `inherit` flag to `addenv()` to allow keeping this behavior if it is actually desired (this might make sense if you are constructing `.env` blocks over a series of `addenv()` calls and you don't want to have to special-case your first operation as a `setenv()` rather than an `addenv()`. (cherry picked from commit fa14d0b)
1 parent d89e619 commit 7224671

File tree

2 files changed

+35
-8
lines changed

2 files changed

+35
-8
lines changed

base/cmd.jl

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,19 @@ setenv(cmd::Cmd, env::Pair{<:AbstractString}...; dir="") =
246246
setenv(cmd::Cmd; dir="") = Cmd(cmd; dir=dir)
247247

248248
"""
249-
addenv(command::Cmd, env...)
249+
addenv(command::Cmd, env...; inherit::Bool = true)
250250
251251
Merge new environment mappings into the given `Cmd` object, returning a new `Cmd` object.
252-
Duplicate keys are replaced.
252+
Duplicate keys are replaced. If `command` does not contain any environment values set already,
253+
it inherits the current environment at time of `addenv()` call if `inherit` is `true`.
253254
"""
254-
function addenv(cmd::Cmd, env::Dict)
255+
function addenv(cmd::Cmd, env::Dict; inherit::Bool = true)
255256
new_env = Dict{String,String}()
256-
if cmd.env !== nothing
257+
if cmd.env === nothing
258+
if inherit
259+
merge!(new_env, ENV)
260+
end
261+
else
257262
for (k, v) in split.(cmd.env, "=")
258263
new_env[string(k)::String] = string(v)::String
259264
end
@@ -264,12 +269,12 @@ function addenv(cmd::Cmd, env::Dict)
264269
return setenv(cmd, new_env)
265270
end
266271

267-
function addenv(cmd::Cmd, pairs::Pair{<:AbstractString}...)
268-
return addenv(cmd, Dict(k => v for (k, v) in pairs))
272+
function addenv(cmd::Cmd, pairs::Pair{<:AbstractString}...; inherit::Bool = true)
273+
return addenv(cmd, Dict(k => v for (k, v) in pairs); inherit)
269274
end
270275

271-
function addenv(cmd::Cmd, env::Vector{<:AbstractString})
272-
return addenv(cmd, Dict(k => v for (k, v) in split.(env, "=")))
276+
function addenv(cmd::Cmd, env::Vector{<:AbstractString}; inherit::Bool = true)
277+
return addenv(cmd, Dict(k => v for (k, v) in split.(env, "=")); inherit)
273278
end
274279

275280
(&)(left::AbstractCmd, right::AbstractCmd) = AndCmds(left, right)

test/spawn.jl

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,28 @@ end
711711
@test strip(String(read(cmd))) == "bar bar"
712712
cmd = addenv(cmd, ["FOO=baz"])
713713
@test strip(String(read(cmd))) == "baz bar"
714+
715+
# Test that `addenv()` works properly with `inherit`
716+
withenv("FOO" => "foo") do
717+
cmd = Cmd(`$shcmd -c "echo \$FOO \$BAR"`)
718+
@test strip(String(read(cmd))) == "foo"
719+
720+
cmd2 = addenv(cmd, "BAR" => "bar"; inherit=false)
721+
@test strip(String(read(cmd2))) == "bar"
722+
723+
cmd2 = addenv(cmd, "BAR" => "bar"; inherit=true)
724+
@test strip(String(read(cmd2))) == "foo bar"
725+
726+
# Changing the environment doesn't effect the command,
727+
# because it was baked in at `addenv()` time
728+
withenv("FOO" => "baz") do
729+
@test strip(String(read(cmd2))) == "foo bar"
730+
end
731+
732+
# Even with inheritance, `addenv()` dominates:
733+
cmd2 = addenv(cmd, "FOO" => "foo2", "BAR" => "bar"; inherit=true)
734+
@test strip(String(read(cmd2))) == "foo2 bar"
735+
end
714736
end
715737

716738

0 commit comments

Comments
 (0)