Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(283)

Side by Side Diff: sdk/lib/_internal/pub/lib/src/solver/solve_report.dart

Issue 103453005: Show detailed report on upgrade. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 '../lock_file.dart';
8 import '../log.dart' as log;
9 import '../package.dart';
10 import '../source_registry.dart';
11 import '../utils.dart';
12 import 'version_solver.dart';
13
14 /// Generates and displays nicely formatted reports for the results of running
15 /// a version resolution.
16 class SolveReport {
nweiz 2013/12/11 06:48:32 At first glance the fact that this is different th
Bob Nystrom 2013/12/11 22:36:59 Added some more docs clarifying.
nweiz 2013/12/11 23:31:27 I do. Exporting a class instead of a function impl
Bob Nystrom 2013/12/12 00:14:58 Done.
17 final SourceRegistry _sources;
18 final Package _root;
19 final LockFile _previousLockFile;
20 final SolveResult _result;
21
22 /// The dependencies in [_result], keyed by package name.
23 final _dependencies = new Map<String, PackageId>();
24
25 final _output = new StringBuffer();
26
27 /// To avoid emitting trailing newlines, we track if any are needed and only
28 /// emit then when text on the next line is about to be written.
29 int _pendingLines = 0;
nweiz 2013/12/11 06:48:32 This is pretty general behavior. It would be nice
Bob Nystrom 2013/12/11 22:36:59 Added a TODO. I like the idea, but I can't come up
nweiz 2013/12/11 23:31:27 I'm not a big fan of the philosophy of "postpone t
30
31 SolveReport(this._sources, this._root, this._previousLockFile, this._result) {
32 // Fill the map so we can use it later.
33 for (var id in _result.packages) {
34 _dependencies[id.name] = id;
35 }
36 }
37
38 /// Displays a report of the results of the version resolution relative to
39 /// the previous lock file.
40 ///
41 /// If [showAll] is true, then all of the previous and current dependencies
42 /// are shown and their changes relative to the previous lock file are
43 /// highlighted. Otherwise, only overrides are shown.
44 ///
45 /// Returns the number of changed dependencies.
46 int show({bool showAll}) {
47 if (showAll) _reportChanges();
48 _reportOverrides();
49
50 // Count how many dependencies actually changed.
51 var dependencies = _dependencies.keys.toSet();
52 dependencies.addAll(_previousLockFile.packages.keys);
53 dependencies.remove(_root.name);
54
55 return dependencies.where((name) {
56 var oldId = _previousLockFile.packages[name];
57 var newId = _dependencies[name];
58
59 // Added or removed dependencies count.
60 if (oldId == null) return true;
61 if (newId == null) return true;
62
63 // The dependency existed before, so see if it was modified.
64 return !_descriptionsEqual(oldId, newId) ||
65 oldId.version != newId.version;
66 }).length;
67 }
68
69 /// Displays a report of all of the previous and current dependencies and
70 /// how they have changed.
71 void _reportChanges() {
72 _output.clear();
nweiz 2013/12/11 06:48:32 Clearing and writing to a StringBuffer instance va
Bob Nystrom 2013/12/11 22:36:59 It's a bit gross to me too, but this class's reaso
73
74 // Show the current dependencies ordered by name.
nweiz 2013/12/11 06:48:32 "current" -> "new"
Bob Nystrom 2013/12/11 22:36:59 I used "current" here because "new" could mean "de
nweiz 2013/12/11 23:31:27 "current" is confusing because it's not clear whic
Bob Nystrom 2013/12/12 00:14:58 Done.
75 var names = _result.packages.map((id) => id.name).toList();
76 names.remove(_root.name);
77 names.sort();
78 names.forEach(_reportPackage);
79
80 // Show any removed ones.
81 var removed = _previousLockFile.packages.keys.toSet();
82 removed.removeAll(names);
83 if (removed.isNotEmpty) {
84 _writeln("These packages are no longer being depended on:");
85 removed = removed.toList();
86 removed.sort();
87 removed.forEach(_reportPackage);
88 }
89
90 log.message(_output.toString());
91 }
92
93 /// Displays a warning about the overrides currently in effect.
94 void _reportOverrides() {
95 _output.clear();
96
97 if (_result.overrides.isNotEmpty) {
98 _writeln("Warning: You are using these overridden dependencies:");
99 var overrides = _result.overrides.map((dep) => dep.name).toList();
100 overrides.sort((a, b) => a.compareTo(b));
101
102 overrides.forEach(
103 (name) => _reportPackage(name, highlightOverride: false));
104
105 log.warning(_output.toString());
106 }
107 }
108
109 /// Reports the results of the upgrade on the package named [name].
110 ///
111 /// If [highlightOverride] is true (or absent), writes "(override)" next to
112 /// overridden packages.
113 void _reportPackage(String name, {bool highlightOverride}) {
114 if (highlightOverride == null) highlightOverride = true;
nweiz 2013/12/11 06:48:32 Blah blah explicit default.
Bob Nystrom 2013/12/11 22:36:59 Previous comment.
115
116 var newId = _dependencies[name];
117 var oldId = _previousLockFile.packages[name];
118 var id = newId != null ? newId : oldId;
119
120 var isOverridden = _result.overrides.map(
121 (dep) => dep.name).contains(id.name);
122
123 var changed = false;
124
125 // Show a one-character "icon" describing the change. They are:
126 //
127 // ! The package is being overridden.
128 // - The package was removed.
129 // + The package was added.
130 // > The package was upgraded from a lower version.
131 // < The package was downgraded from a higher version.
132 // * Any other change between the old and new package.
133 if (isOverridden) {
134 _write(log.magenta("! "));
135 } else if (newId == null) {
136 _write(log.red("- "));
137 } else if (oldId == null) {
138 _write(log.green("+ "));
139 } else if (!_descriptionsEqual(oldId, newId)) {
140 _write(log.cyan("* "));
nweiz 2013/12/11 06:48:32 For colorblind folks like myself, it might be nice
Bob Nystrom 2013/12/11 22:36:59 Added a bunch of docs to the color functions in lo
141 changed = true;
142 } else if (oldId.version < newId.version) {
143 _write(log.green("> "));
144 changed = true;
145 } else if (oldId.version > newId.version) {
146 _write(log.cyan("< "));
147 changed = true;
148 } else {
149 // Unchanged.
150 _write(" ");
151 }
152
153 // If the package was upgraded, show what it was upgraded from.
nweiz 2013/12/11 06:48:32 This comment should be on the next block.
Bob Nystrom 2013/12/11 22:36:59 Done.
154 _write(log.bold(id.name));
155 _write(" ");
156 _writeId(id);
157
158 if (changed) {
159 _write(" (was ");
160 _writeId(oldId);
161 _write(")");
162 }
163
164 // Highlight overridden packages.
165 if (isOverridden && highlightOverride) {
166 _write(" ${log.magenta('(overridden)')}");
167 }
168
169 // See if there are any newer versions of the package that we were
170 // unable to upgrade to.
171 if (newId != null) {
172 var versions = _result.availableVersions[newId.name];
173 var newerStable = 0;
174 var newerUnstable = 0;
175
176 for (var version in versions) {
177 if (version > newId.version) {
178 if (version.isPreRelease) {
179 newerUnstable++;
180 } else {
181 newerStable++;
182 }
183 }
184 }
185
186 // If there are newer stable versions, only show those.
187 var message;
188 if (newerStable > 0) {
189 message = "($newerStable newer "
190 "${pluralize('version', newerStable)} available)";
191 } else if (newerUnstable > 0) {
192 message = "($newerUnstable newer unstable "
193 "${pluralize('version', newerUnstable)} available)";
194 }
195
196 if (message != null) _write(" ${log.cyan(message)}");
197 }
198
199 _writeln();
200 }
201
202 /// Returns `true` if [a] and [b] are from the same source and have the same
203 /// description.
204 bool _descriptionsEqual(PackageId a, PackageId b) {
205 if (a.source != b.source) return false;
206
207 if (_sources.contains(a.source)) {
208 var source = _sources[a.source];
209 return source.descriptionsEqual(a.description, b.description);
210 } else {
211 // Unknown source, so just do a literal comparison.
nweiz 2013/12/11 06:48:32 If it's an unknown source there's no way the versi
Bob Nystrom 2013/12/11 22:36:59 I added a TODO elsewhere for this. What I want to
212 return a.description == b.description;
213 }
214 }
215
216 /// Writes a terse description of [id] (not including its name) to the output.
217 void _writeId(PackageId id) {
218 _write(id.version);
219
220 var source = null;
221 if (_sources.contains(id.source)) {
222 source = _sources[id.source];
223 }
224
225 if (source != null && source != _sources.defaultSource) {
226 var description = source.formatDescription(_root.dir, id.description);
227 _write(" from ${id.source} $description");
228 }
229 }
230
231 /// Writes [obj] to the output.
232 void _write(Object obj) {
233 while (_pendingLines > 0) {
234 _output.writeln();
235 _pendingLines--;
236 }
237 _output.write(obj);
238 }
239
240 /// Writes [obj] (if not null) followed by a newline to the output.
241 ///
242 /// Doesn't actually immediately write. Instead, it waits until output is
nweiz 2013/12/11 06:48:32 "immediately write a newline".
Bob Nystrom 2013/12/11 22:36:59 Done.
243 /// written on the nextline. That way, trailing newlines aren't displayed.
nweiz 2013/12/11 06:48:32 "next line"
Bob Nystrom 2013/12/11 22:36:59 Done.
244 void _writeln([Object obj]) {
245 if (obj != null) _write(obj);
246 _pendingLines++;
247 }
248 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698