OLD | NEW |
| (Empty) |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
2 // for details. All rights reserved. Use of this source code is governed by a | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 library pub.solver.solve_report; | |
6 | |
7 import 'package:pub_semver/pub_semver.dart'; | |
8 | |
9 import '../lock_file.dart'; | |
10 import '../log.dart' as log; | |
11 import '../package.dart'; | |
12 import '../source_registry.dart'; | |
13 import '../utils.dart'; | |
14 import 'version_solver.dart'; | |
15 | |
16 /// Unlike [SolveResult], which is the static data describing a resolution, | |
17 /// this class contains the mutable state used while generating the report | |
18 /// itself. | |
19 /// | |
20 /// It's a report builder. | |
21 class SolveReport { | |
22 final SolveType _type; | |
23 final SourceRegistry _sources; | |
24 final Package _root; | |
25 final LockFile _previousLockFile; | |
26 final SolveResult _result; | |
27 | |
28 /// The dependencies in [_result], keyed by package name. | |
29 final _dependencies = new Map<String, PackageId>(); | |
30 | |
31 final _output = new StringBuffer(); | |
32 | |
33 SolveReport(this._type, this._sources, this._root, this._previousLockFile, | |
34 this._result) { | |
35 // Fill the map so we can use it later. | |
36 for (var id in _result.packages) { | |
37 _dependencies[id.name] = id; | |
38 } | |
39 } | |
40 | |
41 /// Displays a report of the results of the version resolution relative to | |
42 /// the previous lock file. | |
43 void show() { | |
44 _reportChanges(); | |
45 _reportOverrides(); | |
46 } | |
47 | |
48 /// Displays a one-line message summarizing what changes were made (or would | |
49 /// be made) to the lockfile. | |
50 /// | |
51 /// If [dryRun] is true, describes it in terms of what would be done. | |
52 void summarize({bool dryRun: false}) { | |
53 // Count how many dependencies actually changed. | |
54 var dependencies = _dependencies.keys.toSet(); | |
55 dependencies.addAll(_previousLockFile.packages.keys); | |
56 dependencies.remove(_root.name); | |
57 | |
58 var numChanged = dependencies.where((name) { | |
59 var oldId = _previousLockFile.packages[name]; | |
60 var newId = _dependencies[name]; | |
61 | |
62 // Added or removed dependencies count. | |
63 if (oldId == null) return true; | |
64 if (newId == null) return true; | |
65 | |
66 // The dependency existed before, so see if it was modified. | |
67 return !_sources.idsEqual(oldId, newId); | |
68 }).length; | |
69 | |
70 if (dryRun) { | |
71 if (numChanged == 0) { | |
72 log.message("No dependencies would change."); | |
73 } else if (numChanged == 1) { | |
74 log.message("Would change $numChanged dependency."); | |
75 } else { | |
76 log.message("Would change $numChanged dependencies."); | |
77 } | |
78 } else { | |
79 if (numChanged == 0) { | |
80 if (_type == SolveType.GET) { | |
81 log.message("Got dependencies!"); | |
82 } else { | |
83 log.message("No dependencies changed."); | |
84 } | |
85 } else if (numChanged == 1) { | |
86 log.message("Changed $numChanged dependency!"); | |
87 } else { | |
88 log.message("Changed $numChanged dependencies!"); | |
89 } | |
90 } | |
91 } | |
92 | |
93 /// Displays a report of all of the previous and current dependencies and | |
94 /// how they have changed. | |
95 void _reportChanges() { | |
96 _output.clear(); | |
97 | |
98 // Show the new set of dependencies ordered by name. | |
99 var names = _result.packages.map((id) => id.name).toList(); | |
100 names.remove(_root.name); | |
101 names.sort(); | |
102 names.forEach(_reportPackage); | |
103 | |
104 // Show any removed ones. | |
105 var removed = _previousLockFile.packages.keys.toSet(); | |
106 removed.removeAll(names); | |
107 if (removed.isNotEmpty) { | |
108 _output.writeln("These packages are no longer being depended on:"); | |
109 removed = removed.toList(); | |
110 removed.sort(); | |
111 removed.forEach((name) => _reportPackage(name, alwaysShow: true)); | |
112 } | |
113 | |
114 log.message(_output); | |
115 } | |
116 | |
117 /// Displays a warning about the overrides currently in effect. | |
118 void _reportOverrides() { | |
119 _output.clear(); | |
120 | |
121 if (_result.overrides.isNotEmpty) { | |
122 _output.writeln("Warning: You are using these overridden dependencies:"); | |
123 var overrides = _result.overrides.map((dep) => dep.name).toList(); | |
124 overrides.sort((a, b) => a.compareTo(b)); | |
125 | |
126 overrides.forEach( | |
127 (name) => _reportPackage(name, alwaysShow: true, | |
128 highlightOverride: false)); | |
129 | |
130 log.warning(_output); | |
131 } | |
132 } | |
133 | |
134 /// Reports the results of the upgrade on the package named [name]. | |
135 /// | |
136 /// If [alwaysShow] is true, the package is reported even if it didn't change, | |
137 /// regardless of [_type]. If [highlightOverride] is true (or absent), writes | |
138 /// "(override)" next to overridden packages. | |
139 void _reportPackage(String name, | |
140 {bool alwaysShow: false, bool highlightOverride: true}) { | |
141 var newId = _dependencies[name]; | |
142 var oldId = _previousLockFile.packages[name]; | |
143 var id = newId != null ? newId : oldId; | |
144 | |
145 var isOverridden = _result.overrides.map( | |
146 (dep) => dep.name).contains(id.name); | |
147 | |
148 // If the package was previously a dependency but the dependency has | |
149 // changed in some way. | |
150 var changed = false; | |
151 | |
152 // If the dependency was added or removed. | |
153 var addedOrRemoved = false; | |
154 | |
155 // Show a one-character "icon" describing the change. They are: | |
156 // | |
157 // ! The package is being overridden. | |
158 // - The package was removed. | |
159 // + The package was added. | |
160 // > The package was upgraded from a lower version. | |
161 // < The package was downgraded from a higher version. | |
162 // * Any other change between the old and new package. | |
163 var icon; | |
164 if (isOverridden) { | |
165 icon = log.magenta("! "); | |
166 } else if (newId == null) { | |
167 icon = log.red("- "); | |
168 addedOrRemoved = true; | |
169 } else if (oldId == null) { | |
170 icon = log.green("+ "); | |
171 addedOrRemoved = true; | |
172 } else if (!_sources.idDescriptionsEqual(oldId, newId)) { | |
173 icon = log.cyan("* "); | |
174 changed = true; | |
175 } else if (oldId.version < newId.version) { | |
176 icon = log.green("> "); | |
177 changed = true; | |
178 } else if (oldId.version > newId.version) { | |
179 icon = log.cyan("< "); | |
180 changed = true; | |
181 } else { | |
182 // Unchanged. | |
183 icon = " "; | |
184 } | |
185 | |
186 if (_type == SolveType.GET && !(alwaysShow || changed || addedOrRemoved)) { | |
187 return; | |
188 } | |
189 | |
190 _output.write(icon); | |
191 _output.write(log.bold(id.name)); | |
192 _output.write(" "); | |
193 _writeId(id); | |
194 | |
195 // If the package was upgraded, show what it was upgraded from. | |
196 if (changed) { | |
197 _output.write(" (was "); | |
198 _writeId(oldId); | |
199 _output.write(")"); | |
200 } | |
201 | |
202 // Highlight overridden packages. | |
203 if (isOverridden && highlightOverride) { | |
204 _output.write(" ${log.magenta('(overridden)')}"); | |
205 } | |
206 | |
207 // See if there are any newer versions of the package that we were | |
208 // unable to upgrade to. | |
209 if (newId != null && _type != SolveType.DOWNGRADE) { | |
210 var versions = _result.availableVersions[newId.name]; | |
211 | |
212 var newerStable = false; | |
213 var newerUnstable = false; | |
214 | |
215 for (var version in versions) { | |
216 if (version > newId.version) { | |
217 if (version.isPreRelease) { | |
218 newerUnstable = true; | |
219 } else { | |
220 newerStable = true; | |
221 } | |
222 } | |
223 } | |
224 | |
225 // If there are newer stable versions, only show those. | |
226 var message; | |
227 if (newerStable) { | |
228 message = "(${maxAll(versions, Version.prioritize)} available)"; | |
229 } else if (newerUnstable) { | |
230 message = "(${maxAll(versions)} available)"; | |
231 } | |
232 | |
233 if (message != null) _output.write(" ${log.cyan(message)}"); | |
234 } | |
235 | |
236 _output.writeln(); | |
237 } | |
238 | |
239 /// Writes a terse description of [id] (not including its name) to the output. | |
240 void _writeId(PackageId id) { | |
241 _output.write(id.version); | |
242 | |
243 var source = _sources[id.source]; | |
244 if (source != _sources.defaultSource) { | |
245 var description = source.formatDescription(_root.dir, id.description); | |
246 _output.write(" from ${id.source} $description"); | |
247 } | |
248 } | |
249 } | |
OLD | NEW |