-
Notifications
You must be signed in to change notification settings - Fork 26
/
DependencyGraph.kt
111 lines (85 loc) · 2.52 KB
/
DependencyGraph.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package com.jraska.github.client.graph
class DependencyGraph() {
private val nodes = mutableMapOf<String, Node>()
fun findRoot(): Node {
require(nodes.isNotEmpty()) { "Dependency Tree is empty" }
val rootCandidates = nodes().toMutableSet()
nodes().flatMap { it.dependsOn }
.forEach { rootCandidates.remove(it) }
return rootCandidates.associateBy { heightOf(it.key) }
.maxBy { it.key }!!.value
}
fun nodes(): Collection<Node> = nodes.values
fun longestPath(): LongestPath {
return longestPath(findRoot().key)
}
fun longestPath(key: String): LongestPath {
val nodeNames = nodes.getValue(key)
.longestPath()
.map { it.key }
return LongestPath(nodeNames)
}
fun height(): Int {
return heightOf(findRoot().key)
}
fun heightOf(key: String): Int {
return nodes.getValue(key).height()
}
fun statistics(): GraphStatistics {
val height = height()
val edgesCount = countEdges()
return GraphStatistics(
modulesCount = nodes.size,
edgesCount = edgesCount,
height = height
)
}
fun subTree(key: String): DependencyGraph {
val dependencyTree = DependencyGraph()
addConnections(nodes.getValue(key), dependencyTree)
return dependencyTree
}
private fun addConnections(node: Node, into: DependencyGraph) {
node.dependsOn.forEach {
into.addEdge(node.key, it.key)
addConnections(it, into)
}
}
private fun addEdge(from: String, to: String) {
getOrCreate(from).dependsOn.add(getOrCreate(to))
}
private fun countEdges(): Int {
return nodes().flatMap { node -> node.dependsOn }.count()
}
private fun getOrCreate(key: String): Node {
return nodes[key] ?: Node(key).also { nodes[key] = it }
}
class Node(val key: String) {
val dependsOn = mutableSetOf<Node>()
private fun isLeaf() = dependsOn.isEmpty()
fun height(): Int {
if (isLeaf()) {
return 0
} else {
return 1 + dependsOn.map { it.height() }.max()!!
}
}
internal fun longestPath(): List<Node> {
if (isLeaf()) {
return listOf(this)
} else {
val path = mutableListOf<Node>(this)
val maxHeightNode = dependsOn.maxBy { it.height() }!!
path.addAll(maxHeightNode.longestPath())
return path
}
}
}
companion object {
fun create(dependencies: List<Pair<String, String>>): DependencyGraph {
val graph = DependencyGraph()
dependencies.forEach { graph.addEdge(it.first, it.second) }
return graph
}
}
}