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

Unified 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: Revise again. 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
diff --git a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
new file mode 100644
index 0000000000000000000000000000000000000000..086e7aeaf3366e3d7d1a690c27ee738b4ff56ae2
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
@@ -0,0 +1,262 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library pub.solver.solve_report;
+
+import '../lock_file.dart';
+import '../log.dart' as log;
+import '../package.dart';
+import '../source_registry.dart';
+import '../utils.dart';
+import 'version_solver.dart';
+
+int show(SourceRegistry sources, Package root, LockFile previousLockFile,
nweiz 2013/12/12 21:20:10 Add a doc comment (maybe just combine the existing
+ SolveResult result, {bool showAll: false}) {
+ var report = new _SolveReport(sources, root, previousLockFile, result);
+ return report.show(showAll: showAll);
+}
+
+/// Generates and displays nicely formatted reports for the results of running
+/// a version resolution.
+///
+/// Unlike [SolveResult] which is the static data describing a resolution, this
+/// class contains the mutable state used while generating the report itself.
+/// It's a report builder.
+class _SolveReport {
+ final SourceRegistry _sources;
+ final Package _root;
+ final LockFile _previousLockFile;
+ final SolveResult _result;
+
+ /// The dependencies in [_result], keyed by package name.
+ final _dependencies = new Map<String, PackageId>();
+
+ final _output = new StringBuffer();
+
+ /// To avoid emitting trailing newlines, we track if any are needed and only
+ /// emit then when text on the next line is about to be written.
+ // TODO(rnystrom): Move this into a separate class that wraps any StringSink
+ // with this logic.
+ int _pendingLines = 0;
+
+ _SolveReport(this._sources, this._root, this._previousLockFile,
+ this._result) {
+ // Fill the map so we can use it later.
+ for (var id in _result.packages) {
+ _dependencies[id.name] = id;
+ }
+ }
+
+ /// Displays a report of the results of the version resolution relative to
+ /// the previous lock file.
+ ///
+ /// If [showAll] is true, then all of the previous and current dependencies
+ /// are shown and their changes relative to the previous lock file are
+ /// highlighted. Otherwise, only overrides are shown.
+ ///
+ /// Returns the number of changed dependencies.
+ int show({bool showAll: false}) {
+ if (showAll) _reportChanges();
+ _reportOverrides();
+
+ // Count how many dependencies actually changed.
+ var dependencies = _dependencies.keys.toSet();
+ dependencies.addAll(_previousLockFile.packages.keys);
+ dependencies.remove(_root.name);
+
+ return dependencies.where((name) {
+ var oldId = _previousLockFile.packages[name];
+ var newId = _dependencies[name];
+
+ // Added or removed dependencies count.
+ if (oldId == null) return true;
+ if (newId == null) return true;
+
+ // The dependency existed before, so see if it was modified.
+ return !_descriptionsEqual(oldId, newId) ||
+ oldId.version != newId.version;
+ }).length;
+ }
+
+ /// Displays a report of all of the previous and current dependencies and
+ /// how they have changed.
+ void _reportChanges() {
+ _output.clear();
+
+ // Show the new set of dependencies ordered by name.
+ var names = _result.packages.map((id) => id.name).toList();
+ names.remove(_root.name);
+ names.sort();
+ names.forEach(_reportPackage);
+
+ // Show any removed ones.
+ var removed = _previousLockFile.packages.keys.toSet();
+ removed.removeAll(names);
+ if (removed.isNotEmpty) {
+ _writeln("These packages are no longer being depended on:");
+ removed = removed.toList();
+ removed.sort();
+ removed.forEach(_reportPackage);
+ }
+
+ log.message(_output.toString());
+ }
+
+ /// Displays a warning about the overrides currently in effect.
+ void _reportOverrides() {
+ _output.clear();
+
+ if (_result.overrides.isNotEmpty) {
+ _writeln("Warning: You are using these overridden dependencies:");
+ var overrides = _result.overrides.map((dep) => dep.name).toList();
+ overrides.sort((a, b) => a.compareTo(b));
+
+ overrides.forEach(
+ (name) => _reportPackage(name, highlightOverride: false));
+
+ log.warning(_output.toString());
+ }
+ }
+
+ /// Reports the results of the upgrade on the package named [name].
+ ///
+ /// If [highlightOverride] is true (or absent), writes "(override)" next to
+ /// overridden packages.
+ void _reportPackage(String name, {bool highlightOverride}) {
+ if (highlightOverride == null) highlightOverride = true;
+
+ var newId = _dependencies[name];
+ var oldId = _previousLockFile.packages[name];
+ var id = newId != null ? newId : oldId;
+
+ var isOverridden = _result.overrides.map(
+ (dep) => dep.name).contains(id.name);
+
+ var changed = false;
+
+ // Show a one-character "icon" describing the change. They are:
+ //
+ // ! The package is being overridden.
+ // - The package was removed.
+ // + The package was added.
+ // > The package was upgraded from a lower version.
+ // < The package was downgraded from a higher version.
+ // * Any other change between the old and new package.
+ if (isOverridden) {
+ _write(log.magenta("! "));
+ } else if (newId == null) {
+ _write(log.red("- "));
+ } else if (oldId == null) {
+ _write(log.green("+ "));
+ } else if (!_descriptionsEqual(oldId, newId)) {
+ _write(log.cyan("* "));
+ changed = true;
+ } else if (oldId.version < newId.version) {
+ _write(log.green("> "));
+ changed = true;
+ } else if (oldId.version > newId.version) {
+ _write(log.cyan("< "));
+ changed = true;
+ } else {
+ // Unchanged.
+ _write(" ");
+ }
+
+ _write(log.bold(id.name));
+ _write(" ");
+ _writeId(id);
+
+ // If the package was upgraded, show what it was upgraded from.
+ if (changed) {
+ _write(" (was ");
+ _writeId(oldId);
+ _write(")");
+ }
+
+ // Highlight overridden packages.
+ if (isOverridden && highlightOverride) {
+ _write(" ${log.magenta('(overridden)')}");
+ }
+
+ // See if there are any newer versions of the package that we were
+ // unable to upgrade to.
+ if (newId != null) {
+ var versions = _result.availableVersions[newId.name];
+ var newerStable = 0;
+ var newerUnstable = 0;
+
+ for (var version in versions) {
+ if (version > newId.version) {
+ if (version.isPreRelease) {
+ newerUnstable++;
+ } else {
+ newerStable++;
+ }
+ }
+ }
+
+ // If there are newer stable versions, only show those.
+ var message;
+ if (newerStable > 0) {
+ message = "($newerStable newer "
+ "${pluralize('version', newerStable)} available)";
+ } else if (newerUnstable > 0) {
+ message = "($newerUnstable newer unstable "
+ "${pluralize('version', newerUnstable)} available)";
+ }
+
+ if (message != null) _write(" ${log.cyan(message)}");
+ }
+
+ _writeln();
+ }
+
+ /// Returns `true` if [a] and [b] are from the same source and have the same
+ /// description.
+ bool _descriptionsEqual(PackageId a, PackageId b) {
+ if (a.source != b.source) return false;
+
+ if (_sources.contains(a.source)) {
+ var source = _sources[a.source];
+ return source.descriptionsEqual(a.description, b.description);
+ } else {
+ // Unknown source, so just do a literal comparison.
+ return a.description == b.description;
+ }
+ }
+
+ /// Writes a terse description of [id] (not including its name) to the output.
+ void _writeId(PackageId id) {
+ _write(id.version);
+
+ var source = null;
+ if (_sources.contains(id.source)) {
+ source = _sources[id.source];
+ }
+
+ if (source != null && source != _sources.defaultSource) {
+ var description = source.formatDescription(_root.dir, id.description);
+ _write(" from ${id.source} $description");
+ }
+ }
+
+ /// Writes [obj] to the output.
+ void _write(Object obj) {
+ while (_pendingLines > 0) {
+ _output.writeln();
+ _pendingLines--;
+ }
+ _output.write(obj);
+ }
+
+ /// Writes [obj] (if not null) followed by a newline to the output.
+ ///
+ /// Doesn't actually immediately write a newline. Instead, it waits until
+ /// output is written on the next line. That way, trailing newlines aren't
+ /// displayed.
+ void _writeln([Object obj]) {
+ if (obj != null) _write(obj);
+ _pendingLines++;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698