2024-09-06 21:03:17 -07:00
|
|
|
# Show a Tomo dependency graph
|
2024-09-06 20:02:15 -07:00
|
|
|
|
2025-04-01 12:15:28 -07:00
|
|
|
use patterns
|
|
|
|
|
2024-09-16 10:54:47 -07:00
|
|
|
_USAGE := "Usage: tomodeps <files...>"
|
2024-09-06 21:03:17 -07:00
|
|
|
|
2024-09-06 21:26:30 -07:00
|
|
|
_HELP := "
|
2024-09-16 10:54:47 -07:00
|
|
|
tomodeps: Show a file dependency graph for Tomo source files.
|
2024-09-06 21:26:30 -07:00
|
|
|
$_USAGE
|
2024-09-06 21:03:17 -07:00
|
|
|
"
|
|
|
|
|
2024-09-09 13:54:20 -07:00
|
|
|
enum Dependency(File(path:Path), Module(name:Text))
|
2024-09-06 21:26:30 -07:00
|
|
|
|
2025-04-06 13:36:40 -07:00
|
|
|
func _get_file_dependencies(file:Path -> |Dependency|)
|
2025-04-06 13:07:23 -07:00
|
|
|
if not file.is_file()
|
2025-04-06 10:40:17 -07:00
|
|
|
say("Could not read file: $file")
|
2025-04-06 13:34:23 -07:00
|
|
|
return ||
|
2024-09-06 21:03:17 -07:00
|
|
|
|
2025-04-06 16:20:07 -07:00
|
|
|
deps : @|Dependency|
|
2025-04-06 13:07:23 -07:00
|
|
|
if lines := file.by_line()
|
|
|
|
for line in lines
|
|
|
|
if line.matches_pattern($Pat/use {..}.tm/)
|
2025-04-06 19:26:12 -07:00
|
|
|
file_import := Path.from_text(line.replace_pattern($Pat/use {..}/, "@1")).resolved(relative_to=file)
|
2025-04-06 11:20:18 -07:00
|
|
|
deps.add(Dependency.File(file_import))
|
2025-04-06 13:07:23 -07:00
|
|
|
else if line.matches_pattern($Pat/use {id}/)
|
2025-04-06 19:26:12 -07:00
|
|
|
module_name := line.replace_pattern($Pat/use {..}/, "@1")
|
2025-04-06 11:20:18 -07:00
|
|
|
deps.add(Dependency.Module(module_name))
|
2024-11-09 14:26:01 -08:00
|
|
|
return deps[]
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:36:40 -07:00
|
|
|
func _build_dependency_graph(dep:Dependency, dependencies:@{Dependency=|Dependency|})
|
2025-04-06 11:20:18 -07:00
|
|
|
return if dependencies.has(dep)
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:34:23 -07:00
|
|
|
dependencies[dep] = || # Placeholder
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
dep_deps := when dep is File(path)
|
2024-09-09 13:54:20 -07:00
|
|
|
_get_file_dependencies(path)
|
2025-04-06 13:07:23 -07:00
|
|
|
is Module(module)
|
2024-09-16 10:54:47 -07:00
|
|
|
dir := (~/.local/share/tomo/installed/$module)
|
2025-04-06 16:20:07 -07:00
|
|
|
module_deps : @|Dependency|
|
|
|
|
visited : @|Path|
|
2025-04-06 13:34:23 -07:00
|
|
|
unvisited := @|f.resolved() for f in dir.files() if f.extension() == ".tm"|
|
2025-04-06 13:07:23 -07:00
|
|
|
while unvisited.length > 0
|
2024-09-09 13:54:20 -07:00
|
|
|
file := unvisited.items[-1]
|
2025-04-06 11:20:18 -07:00
|
|
|
unvisited.remove(file)
|
|
|
|
visited.add(file)
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
for file_dep in _get_file_dependencies(file)
|
|
|
|
when file_dep is File(f)
|
|
|
|
if not visited.has(f)
|
2025-04-06 11:20:18 -07:00
|
|
|
unvisited.add(f)
|
2025-04-06 13:07:23 -07:00
|
|
|
is Module(m)
|
2025-04-06 11:20:18 -07:00
|
|
|
module_deps.add(file_dep)
|
2024-11-09 14:26:01 -08:00
|
|
|
module_deps[]
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2024-11-30 12:50:54 -08:00
|
|
|
dependencies[dep] = dep_deps
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
for dep2 in dep_deps
|
2024-09-09 13:54:20 -07:00
|
|
|
_build_dependency_graph(dep2, dependencies)
|
|
|
|
|
2025-04-06 13:36:40 -07:00
|
|
|
func get_dependency_graph(dep:Dependency -> {Dependency=|Dependency|})
|
2025-04-06 16:20:07 -07:00
|
|
|
graph : @{Dependency=|Dependency|}
|
2024-10-27 17:49:03 -07:00
|
|
|
_build_dependency_graph(dep, graph)
|
2024-09-09 13:54:20 -07:00
|
|
|
return graph
|
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
func _printable_name(dep:Dependency -> Text)
|
|
|
|
when dep is Module(module)
|
2025-04-06 19:26:12 -07:00
|
|
|
return "\[34;1]$module\[]"
|
2025-04-06 13:07:23 -07:00
|
|
|
is File(f)
|
2025-04-06 11:20:18 -07:00
|
|
|
f = f.relative_to((.))
|
2025-04-06 13:07:23 -07:00
|
|
|
if f.exists()
|
2025-03-15 11:22:11 -07:00
|
|
|
return Text(f)
|
2025-04-06 13:07:23 -07:00
|
|
|
else
|
2025-04-06 19:26:12 -07:00
|
|
|
return "\[31;1]$f (not found)\[]"
|
2024-09-09 13:54:20 -07:00
|
|
|
|
2025-04-06 13:36:40 -07:00
|
|
|
func _draw_tree(dep:Dependency, dependencies:{Dependency=|Dependency|}, already_printed:@|Dependency|, prefix="", is_last=yes)
|
2025-04-06 13:07:23 -07:00
|
|
|
if already_printed.has(dep)
|
2025-04-06 19:26:12 -07:00
|
|
|
say(prefix ++ (if is_last then "└── " else "├── ") ++ _printable_name(dep) ++ " \[2](recursive)\[]")
|
2024-09-06 21:26:30 -07:00
|
|
|
return
|
2024-09-06 20:02:15 -07:00
|
|
|
|
2025-04-06 13:49:40 -07:00
|
|
|
say(prefix ++ (if is_last then "└── " else "├── ") ++ _printable_name(dep))
|
2025-04-06 11:20:18 -07:00
|
|
|
already_printed.add(dep)
|
2024-09-06 20:02:15 -07:00
|
|
|
|
2025-04-06 13:49:40 -07:00
|
|
|
child_prefix := prefix ++ (if is_last then " " else "│ ")
|
2024-09-06 20:02:15 -07:00
|
|
|
|
2025-04-06 13:34:23 -07:00
|
|
|
children := dependencies[dep] or ||
|
2025-04-06 13:07:23 -07:00
|
|
|
for i,child in children.items
|
2024-09-06 20:02:15 -07:00
|
|
|
is_child_last := (i == children.length)
|
2024-09-06 21:33:07 -07:00
|
|
|
_draw_tree(child, dependencies, already_printed, child_prefix, is_child_last)
|
|
|
|
|
2025-04-06 13:36:40 -07:00
|
|
|
func draw_tree(dep:Dependency, dependencies:{Dependency=|Dependency|})
|
2025-04-06 16:20:07 -07:00
|
|
|
printed : @|Dependency|
|
2024-09-09 13:54:20 -07:00
|
|
|
say(_printable_name(dep))
|
2025-04-06 11:20:18 -07:00
|
|
|
printed.add(dep)
|
2025-04-06 13:34:23 -07:00
|
|
|
deps := dependencies[dep] or ||
|
2025-04-06 13:07:23 -07:00
|
|
|
for i,child in deps.items
|
2024-09-09 13:54:20 -07:00
|
|
|
is_child_last := (i == deps.length)
|
2024-10-27 17:49:03 -07:00
|
|
|
_draw_tree(child, dependencies, already_printed=printed, is_last=is_child_last)
|
2024-09-06 20:02:15 -07:00
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
func main(files:[Text])
|
|
|
|
if files.length == 0
|
2024-09-15 13:42:42 -07:00
|
|
|
exit("
|
2024-09-06 21:35:57 -07:00
|
|
|
Please provide at least one file!
|
|
|
|
$_USAGE
|
|
|
|
")
|
|
|
|
|
2025-04-06 13:07:23 -07:00
|
|
|
for arg in files
|
|
|
|
if arg.matches_pattern($Pat/{..}.tm/)
|
2025-04-06 11:20:18 -07:00
|
|
|
path := Path.from_text(arg).resolved()
|
2024-09-09 14:04:46 -07:00
|
|
|
dependencies := get_dependency_graph(File(path))
|
|
|
|
draw_tree(File(path), dependencies)
|
2025-04-06 13:07:23 -07:00
|
|
|
else if arg.matches_pattern($Pat/{id}/)
|
2024-09-09 14:04:46 -07:00
|
|
|
dependencies := get_dependency_graph(Module(arg))
|
|
|
|
draw_tree(Module(arg), dependencies)
|
2025-04-06 13:07:23 -07:00
|
|
|
else
|
2025-04-06 19:26:12 -07:00
|
|
|
say("\[2]Skipping $arg\[]")
|
2024-09-06 20:02:15 -07:00
|
|
|
skip
|
|
|
|
|