Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 12 additions & 9 deletions src/graph/builder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,7 +1192,18 @@ auto process_import(
if (auto const* env_val = std::getenv(name_buf.c_str())) {
value_id = intern(env_val);
}
// 2. Fall back to cached value from previous build (passed via options)
// 2. If the author wrote `?= default`, that default is the explicit
// revert-target for the env-unset case and wins over the cache.
else if (imp.default_value) {
auto expanded = parser::expand(*ctx.eval, *imp.default_value);
if (!expanded) {
return pup::unexpected<Error>(expanded.error());
}
value_id = *expanded;
}
// 3. No env, no default — fall back to the cached value from the previous
// build so plain `import VAR` stays stable across shell sessions that
// forget to re-export the variable.
else if (auto it = std::lower_bound(
state.options.cached_env_vars.begin(),
state.options.cached_env_vars.end(),
Expand All @@ -1202,14 +1213,6 @@ auto process_import(
it != state.options.cached_env_vars.end() && str(it->first) == var_name_sv) {
value_id = it->second;
}
// 3. Fall back to default value
else if (imp.default_value) {
auto expanded = parser::expand(*ctx.eval, *imp.default_value);
if (!expanded) {
return pup::unexpected<Error>(expanded.error());
}
value_id = *expanded;
}

auto value_sv = str(value_id);

Expand Down
33 changes: 33 additions & 0 deletions test/unit/test_e2e.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4343,6 +4343,39 @@ SCENARIO("import with ?= operator", "[e2e][import]")
}
}

SCENARIO("import ?= default reverts when env is unset on warm index", "[e2e][import]")
{
GIVEN("a Tupfile with import VAR ?= default, after a build that captured the env value")
{
auto f = E2EFixture { "import_soft_set" };

{
auto env = EnvGuard { "MY_VAR", "from_env" };
REQUIRE(f.init().success());
auto build1 = f.build();
REQUIRE(build1.success());
REQUIRE(f.read_file("out.txt") == "from_env\n");
}

WHEN("the env var is unset and the project is rebuilt")
{
auto build2 = f.build();

THEN("build succeeds")
{
INFO("stdout: " << build2.stdout_output);
INFO("stderr: " << build2.stderr_output);
REQUIRE(build2.success());
}

THEN("the default value is restored, not the cached env value")
{
REQUIRE(f.read_file("out.txt") == "default_value\n");
}
}
}
}

// =============================================================================
// Error Handling Tests
// =============================================================================
Expand Down
Loading