mirror of
https://github.com/NixOS/nix
synced 2025-06-30 03:23:16 +02:00
116 lines
3.3 KiB
C++
116 lines
3.3 KiB
C++
#include "input-accessor.hh"
|
|
|
|
namespace nix {
|
|
|
|
// TODO: handle file creation / deletion.
|
|
struct PatchingInputAccessor : InputAccessor
|
|
{
|
|
ref<InputAccessor> next;
|
|
|
|
std::map<CanonPath, std::vector<std::string>> patchesPerFile;
|
|
|
|
PatchingInputAccessor(
|
|
ref<InputAccessor> next,
|
|
const std::vector<std::string> & patches)
|
|
: next(next)
|
|
{
|
|
/* Extract the patches for each file. */
|
|
for (auto & patch : patches) {
|
|
std::string_view p = patch;
|
|
std::string_view start;
|
|
std::string_view fileName;
|
|
|
|
auto flush = [&]()
|
|
{
|
|
if (start.empty()) return;
|
|
auto contents = start.substr(0, p.data() - start.data());
|
|
start = "";
|
|
auto slash = fileName.find('/');
|
|
if (slash == fileName.npos) return;
|
|
fileName = fileName.substr(slash);
|
|
debug("found patch for '%s'", fileName);
|
|
patchesPerFile.emplace(fileName, std::vector<std::string>())
|
|
.first->second.push_back(std::string(contents));
|
|
};
|
|
|
|
while (!p.empty()) {
|
|
auto [line, rest] = getLine(p);
|
|
|
|
if (hasPrefix(line, "--- ")) {
|
|
flush();
|
|
start = p;
|
|
fileName = line.substr(4);
|
|
}
|
|
|
|
if (!start.empty()) {
|
|
if (!(hasPrefix(line, "+++ ")
|
|
|| hasPrefix(line, "@@")
|
|
|| hasPrefix(line, "+")
|
|
|| hasPrefix(line, "-")
|
|
|| hasPrefix(line, " ")
|
|
|| line.empty()))
|
|
{
|
|
flush();
|
|
}
|
|
}
|
|
|
|
p = rest;
|
|
}
|
|
|
|
flush();
|
|
}
|
|
}
|
|
|
|
std::string readFile(const CanonPath & path) override
|
|
{
|
|
auto contents = next->readFile(path);
|
|
|
|
auto i = patchesPerFile.find(path);
|
|
if (i != patchesPerFile.end()) {
|
|
for (auto & patch : i->second) {
|
|
auto tempDir = createTempDir();
|
|
AutoDelete del(tempDir);
|
|
auto sourceFile = tempDir + "/source";
|
|
auto rejFile = tempDir + "/source.rej";
|
|
writeFile(sourceFile, contents);
|
|
try {
|
|
contents = runProgram("patch", true, {"--quiet", sourceFile, "--output=-", "-r", rejFile}, patch);
|
|
} catch (ExecError & e) {
|
|
del.cancel();
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
return contents;
|
|
}
|
|
|
|
bool pathExists(const CanonPath & path) override
|
|
{
|
|
return next->pathExists(path);
|
|
}
|
|
|
|
Stat lstat(const CanonPath & path) override
|
|
{
|
|
return next->lstat(path);
|
|
}
|
|
|
|
DirEntries readDirectory(const CanonPath & path) override
|
|
{
|
|
return next->readDirectory(path);
|
|
}
|
|
|
|
std::string readLink(const CanonPath & path) override
|
|
{
|
|
return next->readLink(path);
|
|
}
|
|
};
|
|
|
|
ref<InputAccessor> makePatchingInputAccessor(
|
|
ref<InputAccessor> next,
|
|
const std::vector<std::string> & patches)
|
|
{
|
|
return make_ref<PatchingInputAccessor>(next, std::move(patches));
|
|
}
|
|
|
|
}
|