Skip to content

Commit

Permalink
Merge pull request atilaneves#289 from kinke/rerun_all_inputs
Browse files Browse the repository at this point in the history
Handle removed/renamed build.ninja/Makefile input *files* too, not just source dirs
  • Loading branch information
atilaneves authored Feb 29, 2024
2 parents b5ec502 + 0a583c3 commit dea9fd3
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 26 deletions.
12 changes: 8 additions & 4 deletions payload/reggae/backend/make.d
Original file line number Diff line number Diff line change
Expand Up @@ -75,9 +75,9 @@ struct Makefile {
//includes rerunning reggae
string output() @safe {

import std.array: join, replace;
import std.array: join;
import std.range: chain;
import std.algorithm: sort, uniq, map;
import std.algorithm: sort, uniq;

auto ret = simpleOutput;

Expand All @@ -87,11 +87,15 @@ struct Makefile {
// add a dependency on the Makefile to reggae itself and the build description,
// but only if not exporting a build
auto srcDirs = _srcDirs.sort.uniq;
const flattenedInputs = chain(options.reggaeFileDependencies, srcDirs).join(" ");
const rerunLine = "\t" ~ options.rerunArgs.join(" ") ~ "\n";

ret ~= fileName() ~ ": " ~ chain(options.reggaeFileDependencies, srcDirs.save).join(" ") ~ "\n";
ret ~= fileName() ~ ": " ~ flattenedInputs ~ "\n";
ret ~= rerunLine;
ret ~= "\n" ~ srcDirs.save.map!(d => d ~ ":" ~ "\n" ~ rerunLine).join("\n");
// Add a dummy target for all Makefile inputs, with an empty recipe, just so
// that re-generating the Makefile isn't blocked by removed/renamed inputs.
// See ninja.d for more details.
ret ~= "\n" ~ flattenedInputs ~ ": ;\n";
}

return replaceEnvVars(ret);
Expand Down
43 changes: 21 additions & 22 deletions payload/reggae/backend/ninja.d
Original file line number Diff line number Diff line change
Expand Up @@ -42,29 +42,28 @@ struct Ninja {
import std.algorithm: sort, uniq, map;
import std.range: chain, only;

auto srcDirs = _srcDirs.sort.uniq;
const files = flattenEntriesInBuildLine(
chain(_options.reggaeFileDependencies, srcDirs).array
);
auto paramLines = _options.oldNinja ? [] : ["pool = console"];

const(NinjaEntry)[] rerunEntries() {
// if exporting the build system, don't include rerunning reggae
if(_options.export_)
return [];
auto rerun = NinjaEntry("build build.ninja: _rerun | " ~ files, paramLines);
// the reason this is needed is because source directories
// can be deleted or renamed. If they are, ninja will
// complain about the missing directories since they are a
// dependency of the build.ninja file for rerunning
// reggae. So we consider them phony targets with no
// dependencies to make that not happen and ninja will
// rerun reggae and change the list of source directories
// accordingly.
auto phonySrcDirs = srcDirs
.map!(a => NinjaEntry("build " ~ a.escapeBuildLine ~ ": phony"))
;
return chain(rerun.only, phonySrcDirs).array;

auto srcDirs = _srcDirs.sort.uniq;
const flattenedInputs = flattenEntriesInBuildLine(
chain(_options.reggaeFileDependencies, srcDirs).array
);
auto paramLines = _options.oldNinja ? [] : ["pool = console"];

auto rerun = NinjaEntry("build build.ninja: _rerun | " ~ flattenedInputs, paramLines);
// the reason this is needed is because inputs (files and
// source directories) can be deleted or renamed. If they are,
// ninja will complain about the missing files/directories
// since they are a dependency of the build.ninja file for
// rerunning reggae. So use a dummy phony target 'outputting'
// all build.ninja inputs, so that ninja will happily rerun
// reggae, which will generate a new build.ninja with an
// updated list of build.ninja inputs.
auto phonyInputs = NinjaEntry("build " ~ flattenedInputs ~ ": phony");
return [rerun, phonyInputs];
}

const defaultOutputs = _build.defaultTargetsOutputs(_projectPath);
Expand Down Expand Up @@ -377,7 +376,7 @@ private:
import std.algorithm: map;
import std.array: join, replace;
return entries
.map!escapeBuildLine
.map!escapePathInBuildLine
.join(" ");
}

Expand Down Expand Up @@ -405,9 +404,9 @@ private:
}
}

private string escapeBuildLine(in string line) @safe pure {
private string escapePathInBuildLine(in string path) @safe pure {
import std.array: replace;
return line.replace(":", "$:").replace(" ", "$ ");
return path.replace(":", "$:").replace(" ", "$ ");
}

struct NinjaEntry {
Expand Down
39 changes: 39 additions & 0 deletions tests/it/runtime/issues.d
Original file line number Diff line number Diff line change
Expand Up @@ -520,5 +520,44 @@ version(DigitalMars) {
mixin(backend).shouldFailToExecute.shouldNotContain(msg);
}
}

@("rerun.deleted.file." ~ backend)
@Tags(backend)
unittest {
import std.file: remove;

with(immutable ReggaeSandbox()) {

writeFile(
"imported.d",
q{
import reggae;
enum myTarget = Target.phony("dummy", "");
}
);
writeFile(
"reggaefile.d",
q{
import imported, reggae;
mixin build!myTarget;
}
);

runReggae("-b", backend, "--verbose");
mixin(backend).shouldExecuteOk;

// delete imported.d and make sure reggae gets rerun
remove(inSandboxPath("imported.d"));

static if(backend == "ninja")
enum msg = "missing and no known rule";
else static if(backend == "make")
enum msg = "No rule to make target";
else
static assert(false, "unknown backend");

mixin(backend).shouldFailToExecute.shouldNotContain(msg);
}
}
}
}

0 comments on commit dea9fd3

Please sign in to comment.