11#include " nix/cmd/command.hh"
22#include " nix/store/store-api.hh"
3+ #include " nix/store/path-references.hh"
34#include " nix/util/source-accessor.hh"
45#include " nix/main/shared.hh"
56
@@ -191,7 +192,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
191192 /* Sort the references by distance to `dependency` to
192193 ensure that the shortest path is printed first. */
193194 std::multimap<size_t , Node *> refs;
194- StringSet hashes ;
195+ StorePathSet refPaths ;
195196
196197 for (auto & ref : node.refs ) {
197198 if (ref == node.path && packagePath != dependencyPath)
@@ -200,7 +201,7 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
200201 if (node2.dist == inf)
201202 continue ;
202203 refs.emplace (node2.dist , &node2);
203- hashes .insert (std::string ( node2.path . hashPart ()) );
204+ refPaths .insert (node2.path );
204205 }
205206
206207 /* For each reference, find the files and symlinks that
@@ -209,58 +210,50 @@ struct CmdWhyDepends : SourceExprCommand, MixOperateOnOptions
209210
210211 auto accessor = store->requireStoreObjectAccessor (node.path );
211212
212- auto visitPath = [&](this auto && recur, const CanonPath & p) -> void {
213- auto st = accessor->maybeLstat (p);
214- assert (st);
215-
216- auto p2 = p.isRoot () ? p.abs () : p.rel ();
217-
218- auto getColour = [&](const std::string & hash) {
219- return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
220- };
221-
222- if (st->type == SourceAccessor::Type::tDirectory) {
223- auto names = accessor->readDirectory (p);
224- for (auto & [name, type] : names)
225- recur (p / name);
226- }
227-
228- else if (st->type == SourceAccessor::Type::tRegular) {
229- auto contents = accessor->readFile (p);
213+ auto getColour = [&](const std::string & hash) {
214+ return hash == dependencyPathHash ? ANSI_GREEN : ANSI_BLUE;
215+ };
230216
231- for (auto & hash : hashes) {
232- auto pos = contents.find (hash);
233- if (pos != std::string::npos) {
234- size_t margin = 32 ;
235- auto pos2 = pos >= margin ? pos - margin : 0 ;
236- hits[hash].emplace_back (
237- fmt (" %s: …%s…" ,
217+ if (precise) {
218+ // Use scanForReferencesDeep to find files containing references
219+ scanForReferencesDeep (*accessor, CanonPath::root, refPaths, [&](FileRefScanResult result) {
220+ auto p2 = result.filePath .isRoot () ? result.filePath .abs () : result.filePath .rel ();
221+ auto st = accessor->lstat (result.filePath );
222+
223+ if (st.type == SourceAccessor::Type::tRegular) {
224+ auto contents = accessor->readFile (result.filePath );
225+
226+ // For each reference found in this file, extract context
227+ for (auto & foundRef : result.foundRefs ) {
228+ std::string hash (foundRef.hashPart ());
229+ auto pos = contents.find (hash);
230+ if (pos != std::string::npos) {
231+ size_t margin = 32 ;
232+ auto pos2 = pos >= margin ? pos - margin : 0 ;
233+ hits[hash].emplace_back (fmt (
234+ " %s: …%s…" ,
238235 p2,
239236 hilite (
240237 filterPrintable (std::string (contents, pos2, pos - pos2 + hash.size () + margin)),
241238 pos - pos2,
242239 StorePath::HashLen,
243240 getColour (hash))));
241+ }
242+ }
243+ } else if (st.type == SourceAccessor::Type::tSymlink) {
244+ auto target = accessor->readLink (result.filePath );
245+
246+ // For each reference found in this symlink, show it
247+ for (auto & foundRef : result.foundRefs ) {
248+ std::string hash (foundRef.hashPart ());
249+ auto pos = target.find (hash);
250+ if (pos != std::string::npos)
251+ hits[hash].emplace_back (
252+ fmt (" %s -> %s" , p2, hilite (target, pos, StorePath::HashLen, getColour (hash))));
244253 }
245254 }
246- }
247-
248- else if (st->type == SourceAccessor::Type::tSymlink) {
249- auto target = accessor->readLink (p);
250-
251- for (auto & hash : hashes) {
252- auto pos = target.find (hash);
253- if (pos != std::string::npos)
254- hits[hash].emplace_back (
255- fmt (" %s -> %s" , p2, hilite (target, pos, StorePath::HashLen, getColour (hash))));
256- }
257- }
258- };
259-
260- // FIXME: should use scanForReferences().
261-
262- if (precise)
263- visitPath (CanonPath::root);
255+ });
256+ }
264257
265258 for (auto & ref : refs) {
266259 std::string hash (ref.second ->path .hashPart ());
0 commit comments