1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-14 14:32:42 +01:00

refactor(libstore): integrate DependencyGraph with store path scanning

Adds buildStorePathGraphFromScan() to bridge the generic DependencyGraph
infrastructure with Nix's store path reference scanning. This enables
building annotated dependency graphs that track which files create which
dependencies.

## New API: buildStorePathGraphFromScan()

**Purpose**: Convert file-level scan results into a StorePath-level graph

**How it works**:
1. Calls scanForReferencesDeep() to find which files contain references
2. For each file that references another store path:
   - Adds edge: rootStorePath → referencedStorePath
   - Attaches FileListEdgeProperty with the file path
3. Returns DependencyGraph<StorePath, FileListEdgeProperty>

**Key benefit**: The graph carries file-level provenance. When you see
an edge A→B, you can query which files in A reference B. Essential for:
- why-depends output showing exact file locations
- Future: detailed cycle error messages

## API Changes

**scanForReferencesDeep() callback signature**:
```cpp
// Before: std::function<void(FileRefScanResult)>
// After:  std::function<void(const FileRefScanResult &)>
```

Pass by const-ref to avoid copying large result structures.

## Usage Example

```cpp
auto graph = buildStorePathGraphFromScan(
    *accessor,
    CanonPath("/nix/store/abc-foo"),
    storePathAbc,
    candidateRefs
);

// Query file annotations
auto edgeProp = graph.getEdgeProperty(storePathAbc, storePathDef);
// edgeProp->files contains files that created this edge
```

## Implementation Details

- Uses DependencyGraph's edge properties feature
- FileListEdgeProperty defined in dependency-graph.hh
- Merges duplicate edges (multiple files → same path)
- Debug logging for discovered edges
- Zero overhead if file-level detail not needed
This commit is contained in:
Bernardo Meurer Costa 2025-10-28 02:49:16 +00:00
parent 13da1ca6d5
commit 40beb50e8f
No known key found for this signature in database
2 changed files with 52 additions and 4 deletions

View file

@ -3,10 +3,12 @@
#include "nix/store/references.hh" #include "nix/store/references.hh"
#include "nix/store/path.hh" #include "nix/store/path.hh"
#include "nix/store/dependency-graph.hh"
#include "nix/util/source-accessor.hh" #include "nix/util/source-accessor.hh"
#include <functional> #include <functional>
#include <vector> #include <vector>
#include <map>
namespace nix { namespace nix {
@ -59,7 +61,7 @@ void scanForReferencesDeep(
SourceAccessor & accessor, SourceAccessor & accessor,
const CanonPath & rootPath, const CanonPath & rootPath,
const StorePathSet & refs, const StorePathSet & refs,
std::function<void(FileRefScanResult)> callback); std::function<void(const FileRefScanResult &)> callback);
/** /**
* Scan a store path tree and return which references appear in which files. * Scan a store path tree and return which references appear in which files.
@ -78,4 +80,25 @@ void scanForReferencesDeep(
std::map<CanonPath, StorePathSet> std::map<CanonPath, StorePathSet>
scanForReferencesDeep(SourceAccessor & accessor, const CanonPath & rootPath, const StorePathSet & refs); scanForReferencesDeep(SourceAccessor & accessor, const CanonPath & rootPath, const StorePathSet & refs);
/**
* Build a StorePath-level dependency graph from file scanning.
*
* This scans the given path for references and builds a graph where:
* - Nodes are StorePaths
* - Edges represent dependencies between StorePaths
* - Edge properties store the files that created each dependency
*
* This unified approach allows both cycle detection and why-depends to share
* the same graph-building logic while maintaining file-level information for
* detailed error messages embedded directly in the graph.
*
* @param accessor Source accessor to read the tree
* @param rootPath Root path to scan
* @param rootStorePath The StorePath that rootPath belongs to
* @param refs Set of store paths to search for
* @return StorePathGraphWithFiles where edge properties contain file lists
*/
DependencyGraph<StorePath, FileListEdgeProperty> buildStorePathGraphFromScan(
SourceAccessor & accessor, const CanonPath & rootPath, const StorePath & rootStorePath, const StorePathSet & refs);
} // namespace nix } // namespace nix

View file

@ -1,4 +1,5 @@
#include "nix/store/path-references.hh" #include "nix/store/path-references.hh"
#include "nix/store/dependency-graph.hh"
#include "nix/util/hash.hh" #include "nix/util/hash.hh"
#include "nix/util/archive.hh" #include "nix/util/archive.hh"
#include "nix/util/source-accessor.hh" #include "nix/util/source-accessor.hh"
@ -62,7 +63,7 @@ void scanForReferencesDeep(
SourceAccessor & accessor, SourceAccessor & accessor,
const CanonPath & rootPath, const CanonPath & rootPath,
const StorePathSet & refs, const StorePathSet & refs,
std::function<void(FileRefScanResult)> callback) std::function<void(const FileRefScanResult &)> callback)
{ {
// Recursive tree walker // Recursive tree walker
auto walk = [&](this auto & self, const CanonPath & path) -> void { auto walk = [&](this auto & self, const CanonPath & path) -> void {
@ -137,11 +138,35 @@ scanForReferencesDeep(SourceAccessor & accessor, const CanonPath & rootPath, con
{ {
std::map<CanonPath, StorePathSet> results; std::map<CanonPath, StorePathSet> results;
scanForReferencesDeep(accessor, rootPath, refs, [&](FileRefScanResult result) { scanForReferencesDeep(accessor, rootPath, refs, [&](const FileRefScanResult & result) {
results[std::move(result.filePath)] = std::move(result.foundRefs); results[result.filePath] = result.foundRefs;
}); });
return results; return results;
} }
DependencyGraph<StorePath, FileListEdgeProperty> buildStorePathGraphFromScan(
SourceAccessor & accessor, const CanonPath & rootPath, const StorePath & rootStorePath, const StorePathSet & refs)
{
DependencyGraph<StorePath, FileListEdgeProperty> graph;
scanForReferencesDeep(accessor, rootPath, refs, [&](const FileRefScanResult & result) {
// All files in this scan belong to rootStorePath
for (const auto & foundRef : result.foundRefs) {
// Add StorePath -> StorePath edge with file metadata
FileListEdgeProperty edgeProp;
edgeProp.files.push_back(result.filePath);
graph.addEdge(rootStorePath, foundRef, std::move(edgeProp));
debug(
"buildStorePathGraphFromScan: %s (in %s) → %s",
rootStorePath.to_string(),
result.filePath.abs(),
foundRef.to_string());
}
});
return graph;
}
} // namespace nix } // namespace nix