mirror of
https://github.com/NixOS/nix
synced 2025-06-24 22:11:15 +02:00
Merge 97e7c75f9e
into 6a74590063
This commit is contained in:
commit
aa2880bd6e
1 changed files with 80 additions and 5 deletions
|
@ -47,6 +47,7 @@ template<> struct hash<git_oid>
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::ostream & operator << (std::ostream & str, const git_oid & oid)
|
std::ostream & operator << (std::ostream & str, const git_oid & oid)
|
||||||
{
|
{
|
||||||
str << git_oid_tostr_s(&oid);
|
str << git_oid_tostr_s(&oid);
|
||||||
|
@ -58,6 +59,78 @@ bool operator == (const git_oid & oid1, const git_oid & oid2)
|
||||||
return git_oid_equal(&oid1, &oid2);
|
return git_oid_equal(&oid1, &oid2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
int matchesDotPlusGit(const std::string& str) {
|
||||||
|
// String must have at least 4 characters (at least one '.' plus "git")
|
||||||
|
if (str.size() < 4) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Count consecutive dots at the beginning
|
||||||
|
size_t dotCount = 0;
|
||||||
|
while (dotCount < str.size() && str[dotCount] == '.') {
|
||||||
|
dotCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have at least one dot
|
||||||
|
if (dotCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// After the dots, check if the remaining string is exactly "git"
|
||||||
|
if ((str.size() == dotCount + 3) &&
|
||||||
|
(str[dotCount] == 'g') &&
|
||||||
|
(str[dotCount + 1] == 'i') &&
|
||||||
|
(str[dotCount + 2] == 't')) {
|
||||||
|
return dotCount;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string escapeDotGit(const std::string& filename) {
|
||||||
|
// Check if this filename matches the pattern of dots followed by "git"
|
||||||
|
int dotCount = matchesDotPlusGit(filename);
|
||||||
|
if (dotCount == 0) {
|
||||||
|
// Not a dot+git pattern, return as is
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string result(dotCount * 2, '.'); // String with 2*dotCount dots
|
||||||
|
result += "git";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string unescapeDotGit(const std::string filename) {
|
||||||
|
// Check if this filename matches the pattern of dots followed by "git"
|
||||||
|
int dotCount = matchesDotPlusGit(filename);
|
||||||
|
// Ensure dots are even for unescaping (must be divisible by 2)
|
||||||
|
if (dotCount == 0 || dotCount % 2 != 0) {
|
||||||
|
// Can't unescape an odd number of dots, return as is
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new string with half the dots plus "git"
|
||||||
|
std::string result(dotCount / 2, '.'); // String with dotCount/2 dots
|
||||||
|
result += "git";
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const git_tree_entry* gitTreebuilderGet(git_treebuilder *bld, std::string name)
|
||||||
|
{
|
||||||
|
auto escapedName = escapeDotGit(name);
|
||||||
|
return git_treebuilder_get(bld, escapedName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string gitTreeEntryName(const git_tree_entry *entry)
|
||||||
|
{
|
||||||
|
auto escapedName = git_tree_entry_name(entry);
|
||||||
|
return unescapeDotGit(escapedName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace nix {
|
namespace nix {
|
||||||
|
|
||||||
struct GitSourceAccessor;
|
struct GitSourceAccessor;
|
||||||
|
@ -767,7 +840,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||||
for (size_t n = 0; n < count; ++n) {
|
for (size_t n = 0; n < count; ++n) {
|
||||||
auto entry = git_tree_entry_byindex(tree.get(), n);
|
auto entry = git_tree_entry_byindex(tree.get(), n);
|
||||||
// FIXME: add to cache
|
// FIXME: add to cache
|
||||||
res.emplace(std::string(git_tree_entry_name(entry)), DirEntry{});
|
res.emplace(std::string(gitTreeEntryName(entry)), DirEntry{});
|
||||||
}
|
}
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
|
@ -828,7 +901,7 @@ struct GitSourceAccessor : SourceAccessor
|
||||||
if (git_tree_entry_dup(Setter(copy), entry))
|
if (git_tree_entry_dup(Setter(copy), entry))
|
||||||
throw Error("dupping tree entry: %s", git_error_last()->message);
|
throw Error("dupping tree entry: %s", git_error_last()->message);
|
||||||
|
|
||||||
auto entryName = std::string_view(git_tree_entry_name(entry));
|
auto entryName = gitTreeEntryName(entry);
|
||||||
|
|
||||||
if (entryName == name)
|
if (entryName == name)
|
||||||
res = copy.get();
|
res = copy.get();
|
||||||
|
@ -999,6 +1072,7 @@ struct GitExportIgnoreSourceAccessor : CachingFilteringSourceAccessor {
|
||||||
return !isExportIgnored(path);
|
return !isExportIgnored(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||||
|
@ -1019,7 +1093,7 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||||
Tree prevTree = nullptr;
|
Tree prevTree = nullptr;
|
||||||
|
|
||||||
if (!pendingDirs.empty() &&
|
if (!pendingDirs.empty() &&
|
||||||
(entry = git_treebuilder_get(pendingDirs.back().builder.get(), name.c_str())))
|
(entry = gitTreebuilderGet(pendingDirs.back().builder.get(), name)))
|
||||||
{
|
{
|
||||||
/* Clone a tree that we've already finished. This happens
|
/* Clone a tree that we've already finished. This happens
|
||||||
if a tarball has directory entries that are not
|
if a tarball has directory entries that are not
|
||||||
|
@ -1057,7 +1131,8 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||||
{
|
{
|
||||||
assert(!pendingDirs.empty());
|
assert(!pendingDirs.empty());
|
||||||
auto & pending = pendingDirs.back();
|
auto & pending = pendingDirs.back();
|
||||||
if (git_treebuilder_insert(nullptr, pending.builder.get(), name.c_str(), &oid, mode))
|
auto escapedName = escapeDotGit(name);
|
||||||
|
if (git_treebuilder_insert(nullptr, pending.builder.get(), escapedName.c_str(), &oid, mode))
|
||||||
throw Error("adding a file to a tree builder: %s", git_error_last()->message);
|
throw Error("adding a file to a tree builder: %s", git_error_last()->message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1188,7 +1263,7 @@ struct GitFileSystemObjectSinkImpl : GitFileSystemObjectSink
|
||||||
for (auto & c : CanonPath(relTargetLeft)) {
|
for (auto & c : CanonPath(relTargetLeft)) {
|
||||||
if (auto builder = std::get_if<git_treebuilder *>(&curDir)) {
|
if (auto builder = std::get_if<git_treebuilder *>(&curDir)) {
|
||||||
assert(*builder);
|
assert(*builder);
|
||||||
if (!(entry = git_treebuilder_get(*builder, std::string(c).c_str())))
|
if (!(entry = gitTreebuilderGet(*builder, std::string(c))))
|
||||||
throw Error("cannot find hard link target '%s' for path '%s'", target, path);
|
throw Error("cannot find hard link target '%s' for path '%s'", target, path);
|
||||||
curDir = *git_tree_entry_id(entry);
|
curDir = *git_tree_entry_id(entry);
|
||||||
} else if (auto oid = std::get_if<git_oid>(&curDir)) {
|
} else if (auto oid = std::get_if<git_oid>(&curDir)) {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue