mirror of
https://github.com/NixOS/nix
synced 2025-06-26 11:41:15 +02:00
Git fetcher: Calculate a fingerprint for dirty workdirs
This restores evaluation caching for dirty Git workdirs.
This commit is contained in:
parent
da7e3be8fc
commit
331bf3e261
3 changed files with 49 additions and 6 deletions
|
@ -437,7 +437,12 @@ struct GitRepoImpl : GitRepo, std::enable_shared_from_this<GitRepoImpl>
|
||||||
{
|
{
|
||||||
if (!(statusFlags & GIT_STATUS_INDEX_DELETED) &&
|
if (!(statusFlags & GIT_STATUS_INDEX_DELETED) &&
|
||||||
!(statusFlags & GIT_STATUS_WT_DELETED))
|
!(statusFlags & GIT_STATUS_WT_DELETED))
|
||||||
info.files.insert(CanonPath(path));
|
info.files.emplace(CanonPath(path),
|
||||||
|
statusFlags == GIT_STATUS_CURRENT
|
||||||
|
? WorkdirInfo::State::Clean
|
||||||
|
: WorkdirInfo::State::Dirty);
|
||||||
|
else
|
||||||
|
info.deletedFiles.insert(CanonPath(path));
|
||||||
if (statusFlags != GIT_STATUS_CURRENT)
|
if (statusFlags != GIT_STATUS_CURRENT)
|
||||||
info.isDirty = true;
|
info.isDirty = true;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1202,6 +1207,15 @@ ref<SourceAccessor> GitRepoImpl::getAccessor(const Hash & rev, bool exportIgnore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename K, typename V>
|
||||||
|
std::set<K> getKeys(const std::map<K, V> & c)
|
||||||
|
{
|
||||||
|
std::set<K> res;
|
||||||
|
for (auto & i : c)
|
||||||
|
res.insert(i.first);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
ref<SourceAccessor> GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError)
|
ref<SourceAccessor> GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool exportIgnore, MakeNotAllowedError makeNotAllowedError)
|
||||||
{
|
{
|
||||||
auto self = ref<GitRepoImpl>(shared_from_this());
|
auto self = ref<GitRepoImpl>(shared_from_this());
|
||||||
|
@ -1214,7 +1228,7 @@ ref<SourceAccessor> GitRepoImpl::getAccessor(const WorkdirInfo & wd, bool export
|
||||||
? makeEmptySourceAccessor()
|
? makeEmptySourceAccessor()
|
||||||
: AllowListSourceAccessor::create(
|
: AllowListSourceAccessor::create(
|
||||||
makeFSSourceAccessor(path),
|
makeFSSourceAccessor(path),
|
||||||
std::set<CanonPath> { wd.files },
|
std::set<CanonPath> { getKeys(wd.files) },
|
||||||
std::move(makeNotAllowedError)).cast<SourceAccessor>();
|
std::move(makeNotAllowedError)).cast<SourceAccessor>();
|
||||||
if (exportIgnore)
|
if (exportIgnore)
|
||||||
return make_ref<GitExportIgnoreSourceAccessor>(self, fileAccessor, std::nullopt);
|
return make_ref<GitExportIgnoreSourceAccessor>(self, fileAccessor, std::nullopt);
|
||||||
|
|
|
@ -55,9 +55,14 @@ struct GitRepo
|
||||||
in the repo yet. */
|
in the repo yet. */
|
||||||
std::optional<Hash> headRev;
|
std::optional<Hash> headRev;
|
||||||
|
|
||||||
|
enum State { Clean, Dirty };
|
||||||
|
|
||||||
/* All files in the working directory that are unchanged,
|
/* All files in the working directory that are unchanged,
|
||||||
modified or added, but excluding deleted files. */
|
modified or added, but excluding deleted files. */
|
||||||
std::set<CanonPath> files;
|
std::map<CanonPath, State> files;
|
||||||
|
|
||||||
|
/* The deleted files. */
|
||||||
|
std::set<CanonPath> deletedFiles;
|
||||||
|
|
||||||
/* The submodules listed in .gitmodules of this workdir. */
|
/* The submodules listed in .gitmodules of this workdir. */
|
||||||
std::vector<Submodule> submodules;
|
std::vector<Submodule> submodules;
|
||||||
|
|
|
@ -685,7 +685,7 @@ struct GitInputScheme : InputScheme
|
||||||
if (getSubmodulesAttr(input))
|
if (getSubmodulesAttr(input))
|
||||||
/* Create mountpoints for the submodules. */
|
/* Create mountpoints for the submodules. */
|
||||||
for (auto & submodule : repoInfo.workdirInfo.submodules)
|
for (auto & submodule : repoInfo.workdirInfo.submodules)
|
||||||
repoInfo.workdirInfo.files.insert(submodule.path);
|
repoInfo.workdirInfo.files.emplace(submodule.path, GitRepo::WorkdirInfo::State::Clean);
|
||||||
|
|
||||||
auto repo = GitRepo::openRepo(repoInfo.url, false, false);
|
auto repo = GitRepo::openRepo(repoInfo.url, false, false);
|
||||||
|
|
||||||
|
@ -793,10 +793,34 @@ struct GitInputScheme : InputScheme
|
||||||
|
|
||||||
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
std::optional<std::string> getFingerprint(ref<Store> store, const Input & input) const override
|
||||||
{
|
{
|
||||||
|
auto makeFingerprint = [&](const Hash & rev)
|
||||||
|
{
|
||||||
|
return rev.gitRev() + (getSubmodulesAttr(input) ? ";s" : "") + (getExportIgnoreAttr(input) ? ";e" : "");
|
||||||
|
};
|
||||||
|
|
||||||
if (auto rev = input.getRev())
|
if (auto rev = input.getRev())
|
||||||
return rev->gitRev() + (getSubmodulesAttr(input) ? ";s" : "") + (getExportIgnoreAttr(input) ? ";e" : "");
|
return makeFingerprint(*rev);
|
||||||
else
|
else {
|
||||||
|
auto repoInfo = getRepoInfo(input);
|
||||||
|
if (repoInfo.isLocal && repoInfo.workdirInfo.headRev) {
|
||||||
|
/* Calculate a fingerprint that takes into account the
|
||||||
|
deleted and modified/added files. */
|
||||||
|
HashSink hashSink{HashAlgorithm::SHA512};
|
||||||
|
for (auto & file : repoInfo.workdirInfo.files)
|
||||||
|
if (file.second == GitRepo::WorkdirInfo::State::Dirty) {
|
||||||
|
writeString("modified:", hashSink);
|
||||||
|
writeString(file.first.abs(), hashSink);
|
||||||
|
readFile(std::filesystem::path(repoInfo.url) + file.first.abs(), hashSink);
|
||||||
|
}
|
||||||
|
for (auto & file : repoInfo.workdirInfo.deletedFiles) {
|
||||||
|
writeString("deleted:", hashSink);
|
||||||
|
writeString(file.abs(), hashSink);
|
||||||
|
}
|
||||||
|
return makeFingerprint(*repoInfo.workdirInfo.headRev)
|
||||||
|
+ ";d=" + hashSink.finish().first.to_string(HashFormat::Base16, false);
|
||||||
|
}
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isLocked(const Input & input) const override
|
bool isLocked(const Input & input) const override
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue