@@ -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+
121200static 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
145269static uint32_t getNixPackages (FFstrbuf * baseDir , const char * dirname )
0 commit comments