Skip to content

Commit fed8b91

Browse files
committed
feat(ImportGraph): add option to exclude imports from other packages (#6151)
Add an option `lake exe graph --to MyProject.XY --noDep` which removes all nodes that do not start in `MyProject`.
1 parent d3bfbe4 commit fed8b91

4 files changed

Lines changed: 56 additions & 3 deletions

File tree

ImportGraph/Main.lean

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Scott Morrison
55
-/
66
import Mathlib.Util.Imports
7+
import Mathlib.Lean.Data.NameMap
78
import Mathlib.Lean.IO.Process
9+
import Mathlib.Lean.Name
810
import Cli
911

1012
/-!
@@ -47,20 +49,24 @@ instance : ParseableType Name where
4749
else
4850
String.toName s
4951

50-
open IO.FS IO.Process in
52+
open IO.FS IO.Process Name in
5153
/-- Implementation of the import graph command line program. -/
5254
def importGraphCLI (args : Cli.Parsed) : IO UInt32 := do
5355
let to := match args.flag? "to" with
5456
| some to => to.as! Name
5557
| none => `Mathlib -- autodetect the main module from the `lakefile.lean`?
5658
let from? := match args.flag? "from" with
57-
| some to => some <| to.as! Name
59+
| some fr => some <| fr.as! Name
5860
| none => none
5961
searchPathRef.set compileTimeSearchPath
6062
let dotFile ← unsafe withImportModules [{module := to}] {} (trustLevel := 1024) fun env => do
6163
let mut graph := env.importGraph
6264
if let .some f := from? then
6365
graph := graph.dependenciesOf (NameSet.empty.insert f)
66+
if ¬(args.hasFlag "include-deps") then
67+
let p := getModule to
68+
graph := graph.filterMap (fun n i =>
69+
if p.isPrefixOf n then (i.filter (isPrefixOf p)) else none)
6470
if args.hasFlag "reduce" then
6571
graph := graph.transitiveReduction
6672
return asDotGraph graph
@@ -83,6 +89,7 @@ def graph : Cmd := `[Cli|
8389
reduce; "Remove transitively redundant edges."
8490
to : Name; "Only show the upstream imports of the specified module."
8591
"from" : Name; "Only show the downstream dependencies of the specified module."
92+
"include-deps"; "Include used files from other projects (e.g. lake packages)"
8693

8794
ARGS:
8895
...outputs : String; "Filename(s) for the output. " ++

Mathlib.lean

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2089,6 +2089,7 @@ import Mathlib.Init.Quot
20892089
import Mathlib.Init.Set
20902090
import Mathlib.Init.ZeroOne
20912091
import Mathlib.Lean.CoreM
2092+
import Mathlib.Lean.Data.NameMap
20922093
import Mathlib.Lean.Elab.Tactic.Basic
20932094
import Mathlib.Lean.EnvExtension
20942095
import Mathlib.Lean.Exception

Mathlib/Lean/Data/NameMap.lean

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/-
2+
Copyright (c) 2023 Jon Eugster. All rights reserved.
3+
Released under Apache 2.0 license as described in the file LICENSE.
4+
Authors: Jon Eugster
5+
-/
6+
import Lean.Data.NameMap
7+
8+
/-!
9+
# Additional functions on `Lean.NameMap`.
10+
11+
We provide `NameMap.filter` and `NameMap.filterMap`.
12+
-/
13+
14+
namespace Lean.NameMap
15+
16+
/--
17+
`filter f m` returns the `NameMap` consisting of all
18+
"`key`/`val`"-pairs in `m` where `f key val` returns `true`.
19+
-/
20+
def filter (f : Name → α → Bool) (m : NameMap α) : NameMap α :=
21+
m.fold process {}
22+
where
23+
process (r : NameMap α) (n : Name) (i : α) :=
24+
if f n i then r.insert n i else r
25+
26+
/--
27+
`filterMap f m` allows to filter a `NameMap` and simultaneously modify the filtered values.
28+
29+
It takes a function `f : Name → α → Option β` and applies `f name` to the value with key `name`.
30+
The resulting entries with non-`none` value are collected to form the output `NameMap`.
31+
-/
32+
def filterMap (f : Name → α → Option β) (m : NameMap α) : NameMap β :=
33+
m.fold process {}
34+
where
35+
process (r : NameMap β) (n : Name) (i : α) :=
36+
match f n i with
37+
| none => r
38+
| some b => r.insert n b

Mathlib/Lean/Name.lean

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import Mathlib.Lean.Expr.Basic
1010
/-!
1111
# Additional functions on `Lean.Name`.
1212
13-
We provide `Name.getModule : Name → CoreM (Option Name)`,
13+
We provide `Name.getModule`,
1414
and `allNames` and `allNamesByModule`.
1515
-/
1616

@@ -48,3 +48,10 @@ def allNamesByModule (p : Name → Bool) : CoreM (Std.HashMap Name (Array Name))
4848
| none => return names.insert m #[n]
4949
else
5050
return names
51+
52+
/-- Returns the very first part of a name: for `Mathlib.Data.Set.Basic` it returns `Mathlib`. -/
53+
def getModule (name : Name) (s := "") : Name :=
54+
match name with
55+
| .anonymous => s
56+
| .num _ _ => panic s!"panic in `getModule`: did not expect numerical name: {name}."
57+
| .str pre s => getModule pre s

0 commit comments

Comments
 (0)