Skip to content

Commit 882b178

Browse files
authored
Packages (nix): use hash to cache count and process count manually (#817)
1 parent bdd2908 commit 882b178

File tree

1 file changed

+133
-9
lines changed

1 file changed

+133
-9
lines changed

src/detection/packages/packages_linux.c

+133-9
Original file line numberDiff line numberDiff line change
@@ -118,28 +118,152 @@ static uint32_t countFilesRecursive(FFstrbuf* baseDir, const char* dirname, cons
118118
return sum;
119119
}
120120

121+
static bool isValidNixPkg(FFstrbuf* pkg)
122+
{
123+
if (!ffPathExists(pkg->chars, FF_PATHTYPE_DIRECTORY))
124+
return false;
125+
126+
ffStrbufSubstrAfterLastC(pkg, '/');
127+
if (
128+
ffStrbufStartsWithS(pkg, "nixos-system-nixos-") ||
129+
ffStrbufEndsWithS(pkg, "-doc") ||
130+
ffStrbufEndsWithS(pkg, "-man") ||
131+
ffStrbufEndsWithS(pkg, "-info") ||
132+
ffStrbufEndsWithS(pkg, "-dev") ||
133+
ffStrbufEndsWithS(pkg, "-bin")
134+
) return false;
135+
136+
enum { START, DIGIT, DOT, MATCH } state = START;
137+
138+
for (uint32_t i = 0; i < pkg->length; i++)
139+
{
140+
char c = pkg->chars[i];
141+
switch (state)
142+
{
143+
case START:
144+
if (c >= '0' && c <= '9')
145+
state = DIGIT;
146+
break;
147+
case DIGIT:
148+
if (c >= '0' && c <= '9')
149+
continue;
150+
if (c == '.')
151+
state = DOT;
152+
else
153+
state = START;
154+
break;
155+
case DOT:
156+
if (c >= '0' && c <= '9')
157+
state = MATCH;
158+
else
159+
state = START;
160+
break;
161+
case MATCH:
162+
break;
163+
}
164+
}
165+
166+
return state == MATCH;
167+
}
168+
169+
static bool checkNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t* count)
170+
{
171+
if (!ffPathExists(cacheDir->chars, FF_PATHTYPE_FILE))
172+
return false;
173+
174+
FF_STRBUF_AUTO_DESTROY cacheContent;
175+
ffStrbufInit(&cacheContent);
176+
if (!ffReadFileBuffer(cacheDir->chars, &cacheContent))
177+
return false;
178+
179+
// Format: <hash>\n<count>
180+
uint32_t split = ffStrbufFirstIndexC(&cacheContent, '\n');
181+
if (split == cacheContent.length)
182+
return false;
183+
184+
ffStrbufSetNS(hash, split, cacheContent.chars);
185+
*count = (uint32_t)atoi(cacheContent.chars + split + 1);
186+
187+
return true;
188+
}
189+
190+
static bool writeNixCache(FFstrbuf* cacheDir, FFstrbuf* hash, uint32_t count)
191+
{
192+
FF_STRBUF_AUTO_DESTROY cacheContent;
193+
ffStrbufInit(&cacheContent);
194+
ffStrbufAppend(&cacheContent, hash);
195+
ffStrbufAppendC(&cacheContent, '\n');
196+
ffStrbufAppendF(&cacheContent, "%u", count);
197+
return ffWriteFileBuffer(cacheDir->chars, &cacheContent);
198+
}
199+
121200
static uint32_t getNixPackagesImpl(char* path)
122201
{
123202
//Nix detection is kinda slow, so we only do it if the dir exists
124203
if(!ffPathExists(path, FF_PATHTYPE_DIRECTORY))
125204
return 0;
126205

127-
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(128);
206+
FF_STRBUF_AUTO_DESTROY cacheDir;
207+
ffStrbufInit(&cacheDir);
208+
ffStrbufAppend(&cacheDir, &instance.state.platform.cacheDir);
209+
ffStrbufEnsureEndsWithC(&cacheDir, '/');
210+
ffStrbufAppendS(&cacheDir, "fastfetch/packages/nix");
211+
ffStrbufAppendS(&cacheDir, path);
212+
213+
//Check the hash first to determine if we need to recompute the count
214+
FF_STRBUF_AUTO_DESTROY hash = ffStrbufCreateA(64);
215+
FF_STRBUF_AUTO_DESTROY cacheHash = ffStrbufCreateA(64);
216+
uint32_t count = 0;
217+
218+
ffProcessAppendStdOut(&hash, (char* const[]) {
219+
"nix-store",
220+
"--query",
221+
"--hash",
222+
path,
223+
NULL
224+
});
225+
226+
if (checkNixCache(&cacheDir, &cacheHash, &count) && ffStrbufEqual(&hash, &cacheHash))
227+
return count;
128228

229+
//Cache is invalid, recompute the count
230+
count = 0;
231+
232+
//Implementation based on bash script from here:
129233
//https://github.com/fastfetch-cli/fastfetch/issues/195#issuecomment-1191748222
130-
FF_STRBUF_AUTO_DESTROY command = ffStrbufCreateA(255);
131-
ffStrbufAppendS(&command, "for x in $(nix-store --query --requisites ");
132-
ffStrbufAppendS(&command, path);
133-
ffStrbufAppendS(&command, "); do if [ -d $x ]; then echo $x ; fi ; done | cut -d- -f2- | egrep '([0-9]{1,}\\.)+[0-9]{1,}' | egrep -v '\\-doc$|\\-man$|\\-info$|\\-dev$|\\-bin$|^nixos-system-nixos-' | uniq | wc -l");
234+
235+
FF_STRBUF_AUTO_DESTROY output = ffStrbufCreateA(1024);
134236

135237
ffProcessAppendStdOut(&output, (char* const[]) {
136-
"sh",
137-
"-c",
138-
command.chars,
238+
"nix-store",
239+
"--query",
240+
"--requisites",
241+
path,
139242
NULL
140243
});
141244

142-
return (uint32_t) strtol(output.chars, NULL, 10);
245+
uint32_t lineLength = 0;
246+
for (uint32_t i = 0; i < output.length; i++)
247+
{
248+
if (output.chars[i] != '\n')
249+
{
250+
lineLength++;
251+
continue;
252+
}
253+
254+
output.chars[i] = '\0';
255+
FFstrbuf line = {
256+
.allocated = 0,
257+
.length = lineLength,
258+
.chars = output.chars + i - lineLength
259+
};
260+
if (isValidNixPkg(&line))
261+
count++;
262+
lineLength = 0;
263+
}
264+
265+
writeNixCache(&cacheDir, &hash, count);
266+
return count;
143267
}
144268

145269
static uint32_t getNixPackages(FFstrbuf* baseDir, const char* dirname)

0 commit comments

Comments
 (0)