Packages (Linux): Improve speed of Guix package detection. (#999)

Instead of waiting for guix to parse the manifest file of a profile
parse it directly by counting "/gnu/store" entries and fitlering out duplicates.

The new implementation now also accounts for propagated-inputs of packages.

Co-authored-by: Carter Li <zhangsongcui3371@sina.com>
This commit is contained in:
Dariqq
2024-06-06 12:06:56 +02:00
committed by GitHub
parent eae73883db
commit 999f52b0b7
+27 -16
View File
@@ -408,26 +408,36 @@ static uint32_t getAM(FFstrbuf* baseDir)
return result;
}
static uint32_t getGuixPackagesImpl(char* path)
static int compareHash(const void* a, const void* b)
{
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(1024);
return memcmp(a, b, 32);
}
ffProcessAppendStdOut(&output, (char* const[]) {
"guix",
"package",
"-p",
path,
"-I",
NULL
});
static uint32_t getGuixPackagesImpl(char* filename)
{
FF_STRBUF_AUTO_DESTROY content = ffStrbufCreate();
if (!ffAppendFileBuffer(filename, &content))
return 0;
// Count number of unique /gnu/store/ paths in PROFILE/manifest based on their hash value.
// Contains packages explicitly installed and their propagated inputs.
char* pend = content.chars;
//Each package is a new line in the output.
// If at least one line is found, add 1 for the last line.
uint32_t count = ffStrbufCountC(&output, '\n');
if(count > 0)
count++;
for (const char* pattern = content.chars; (pattern = strstr(pattern, "/gnu/store/")); pattern += 32)
{
pattern += strlen("/gnu/store/");
memmove(pend, pattern, 32);
pend += 32;
}
if (pend == content.chars)
return 0;
qsort(content.chars, (size_t) (pend - content.chars) / 32, 32, compareHash);
uint32_t count = 1;
for (const char* p = content.chars + 32; p < pend; p += 32)
count += compareHash(p - 32, p) != 0;
return count;
}
@@ -436,6 +446,7 @@ static uint32_t getGuixPackages(FFstrbuf* baseDir, const char* dirname)
{
uint32_t baseDirLength = baseDir->length;
ffStrbufAppendS(baseDir, dirname);
ffStrbufAppendS(baseDir, "/manifest");
uint32_t num_elements = getGuixPackagesImpl(baseDir->chars);
ffStrbufSubstrBefore(baseDir, baseDirLength);
return num_elements;