| 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 |