/
DADependencyChecker.class.st
142 lines (124 loc) · 4.8 KB
/
DADependencyChecker.class.st
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
"
Utility class to easily check dependencies of packages.
DADependencyChecker new dependenciesOf: #CargoPackageManager.
DADependencyChecker new transitiveDependenciesOf: #'CargoPackageManager-Minimal'.
DADependencyChecker new dependentsOf: #CargoPackageManager.
"
Class {
#name : #DADependencyChecker,
#superclass : #Object,
#instVars : [
'report'
],
#category : #'Tool-DependencyAnalyser-Report'
}
{ #category : #private }
DADependencyChecker >> buildPackageRelationGraphFor: aPackageName [
^ [ (DAPackageRelationGraph onPackagesNamed: { aPackageName }) build ]
on: PotentialOutDatedDependencyWarning
do: [ :ex | report addWarning: ex. ex resume ]
]
{ #category : #private }
DADependencyChecker >> computeDependenciesOf: aPackageName [
| dependencies |
dependencies := (self daPackageFor: aPackageName) dependentPackages collect: [:each | each packageName].
^ ((dependencies
addAll: (self manuallyResolvedDependenciesOf: aPackageName);
yourself)
difference: (self ignoredDependenciesOf: aPackageName))
sorted
]
{ #category : #private }
DADependencyChecker >> computeDependenciesOf: aPackageName visitedPackages: visited [
| packageName |
packageName := aPackageName asSymbol.
report
add: packageName
dependencies: (self computeDependenciesOf: packageName).
visited add: packageName
]
{ #category : #'computing - dependencies' }
DADependencyChecker >> computeImageDependencies [
| visited |
self newReport.
report
analysisRunString: 'Pharo image dependencies';
imageVersion: SystemVersion current.
visited := Set new.
RPackageOrganizer default packageNames
do: [ :packageName |
self computeDependenciesOf: packageName visitedPackages: visited ].
^ report
]
{ #category : #private }
DADependencyChecker >> computeTransitiveDependenciesOf: aPackageName visitedPackages: visited [
(visited includes: aPackageName) ifTrue: [ ^ self ].
self computeDependenciesOf: aPackageName visitedPackages: visited.
(self dependenciesOf: aPackageName)
do: [ :each | self computeTransitiveDependenciesOf: each visitedPackages: visited ]
]
{ #category : #private }
DADependencyChecker >> daPackageFor: aPackageName [
^ (((self buildPackageRelationGraphFor: aPackageName) packages)
select: #isSeen) first
]
{ #category : #accessing }
DADependencyChecker >> dependenciesOf: aPackageName [
^ report
dependenciesOf: aPackageName asSymbol
ifAbsentPut: [ self computeDependenciesOf: aPackageName ]
]
{ #category : #private }
DADependencyChecker >> ignoredDependenciesOf: aPackageName [
^ (RPackage organizer packageNamed: aPackageName) ignoredDependencies
]
{ #category : #initialization }
DADependencyChecker >> initialize [
super initialize.
self newReport
]
{ #category : #private }
DADependencyChecker >> manuallyResolvedDependenciesOf: aPackageName [
^ (RPackage organizer packageNamed: aPackageName) manuallyResolvedDependencies
]
{ #category : #initialization }
DADependencyChecker >> newReport [
^ report := DADependencyReport new
]
{ #category : #'computing - dependencies' }
DADependencyChecker >> shortestPathToPackageIntroducingDependency: dependencyPackageName startingFrom: aPackageName [
"This method allows to easily spots a package dependency we want to avoid in the System.
ex: DADependencyChecker new
computeImageDependencies;
shortestPathToPackageIntroducingDependency: #'Athens-Core' startingFrom: 'Monticello'.
The answer will be the shortest path (one, not all) going from #Monticello to #'Athens-Core',
showing dependencies that leads to the introduction of the #'Athens-Core' dependency.
=> #(#Monticello #Kernel #'System-Settings-Core' #'Morphic-Widgets-Windows' #'Rubric' #'Athens-Morphic' #'Athens-Core').
Now, we know that System-Settings-Core brings the whole graphical environment with him and that we should avoid the dependency
between #Kernel and #'System-Settings-Core'."
| dijkstra |
report ifNil: [ ^ self ].
dijkstra := MalDijkstra new.
dijkstra nodes: report dependencies keys.
report dependenciesDo: [ :packageName :dependencies |
dependencies do: [ :dependency |
dijkstra edges: { packageName } from: [ :ignored | packageName ] to: [ :ignored | dependency ] ] ].
dijkstra runFrom: aPackageName to: dependencyPackageName.
^ dijkstra backtrack
]
{ #category : #'computing - dependencies' }
DADependencyChecker >> transitiveDependenciesOf: aPackageName [
self newReport.
report
analysisRunString: 'Transitive dependencies of ' , aPackageName;
imageVersion: SystemVersion current.
self computeTransitiveDependenciesOf: aPackageName visitedPackages: Set new.
^ report
]
{ #category : #accessing }
DADependencyChecker >> unresolvedDependenciesOf: aPackageName [
^ [ (DAMessageSendAnalyzer on: aPackageName) missingMethodsWithPotentialMatchAfterManuallyResolvedDependenciesAddition
reject: #isEmpty ]
on: PotentialOutDatedDependencyWarning
do: [ :ex | ex resume ]
]