Skip to content

Commit 364484f

Browse files
authored
Merge pull request #1779 from dart-lang/feature.solver.error-prep
Various refactors in preparation for adding error reporting
2 parents a7df959 + 3cde899 commit 364484f

13 files changed

+264
-294
lines changed

lib/src/command_runner.dart

+3-3
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ import 'http.dart';
3030
import 'io.dart';
3131
import 'log.dart' as log;
3232
import 'sdk.dart' as sdk;
33-
import 'solver.dart';
3433
import 'utils.dart';
3534

3635
class PubCommandRunner extends CommandRunner {
@@ -232,12 +231,13 @@ and include the logs in an issue on https://github.com/dart-lang/pub/issues/new
232231
int _chooseExitCode(exception) {
233232
while (exception is WrappedException) exception = exception.innerError;
234233

234+
// TODO(nweiz): Emit an UNAVAILABLE exit code for a SolveFailure that was
235+
// (transitively) caused by a package not existing.
235236
if (exception is HttpException ||
236237
exception is http.ClientException ||
237238
exception is SocketException ||
238239
exception is TlsException ||
239-
exception is PubHttpException ||
240-
exception is DependencyNotFoundException) {
240+
exception is PubHttpException) {
241241
return exit_codes.UNAVAILABLE;
242242
} else if (exception is FormatException || exception is DataException) {
243243
return exit_codes.DATA;

lib/src/entrypoint.dart

-2
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,6 @@ class Entrypoint {
214214
}
215215
}
216216

217-
if (!result.succeeded) throw result.error;
218-
219217
result.showReport(type);
220218

221219
if (dryRun) {

lib/src/global_packages.dart

+4-7
Original file line numberDiff line numberDiff line change
@@ -172,14 +172,11 @@ class GlobalPackages {
172172
dependencies: [dep], sources: cache.sources));
173173

174174
// Resolve it and download its dependencies.
175+
//
176+
// TODO(nweiz): If this produces a SolveFailure that's caused by [dep] not
177+
// being available, report that as a [dataError].
175178
var result = await resolveVersions(SolveType.GET, cache, root);
176-
if (!result.succeeded) {
177-
// If the package specified by the user doesn't exist, we want to
178-
// surface that as a [DataError] with the associated exit code.
179-
if (result.error.package != dep.name) throw result.error;
180-
if (result.error is NoVersionException) dataError(result.error.message);
181-
throw result.error;
182-
}
179+
183180
result.showReport(SolveType.GET);
184181

185182
// Make sure all of the dependencies are locally installed.

lib/src/package_name.dart

+22-6
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,7 @@ class PackageRef extends PackageName {
102102
}
103103

104104
String toTerseString() {
105-
if (isMagic) return name;
106-
if (isRoot || source.name != 'hosted') return "$name";
105+
if (isMagic || isRoot || source.name == 'hosted') return name;
107106
return "$name from $source";
108107
}
109108

@@ -157,8 +156,8 @@ class PackageId extends PackageName {
157156
}
158157

159158
String toTerseString() {
160-
if (isMagic) return name;
161-
if (isRoot || source.name == 'hosted') return "$name $version";
159+
if (isMagic || isRoot) return name;
160+
if (source.name == 'hosted') return "$name $version";
162161
return "$name $version from $source";
163162
}
164163
}
@@ -230,8 +229,8 @@ class PackageRange extends PackageName {
230229
}
231230

232231
String toTerseString() {
233-
if (isMagic) return name;
234-
if (isRoot || source.name == 'hosted') return "$name $constraint";
232+
if (isMagic || isRoot) return name;
233+
if (source.name == 'hosted') return "$name $constraint";
235234
return "$name $constraint from $source";
236235
}
237236

@@ -242,6 +241,23 @@ class PackageRange extends PackageName {
242241
features: new Map.from(this.features)..addAll(features));
243242
}
244243

244+
/// Returns a copy of [this] with the same semantics, but with a `^`-style
245+
/// constraint if possible.
246+
PackageRange withTerseConstraint() {
247+
if (constraint is! VersionRange) return this;
248+
if (constraint.toString().startsWith("^")) return this;
249+
250+
var range = constraint as VersionRange;
251+
if (range.includeMin &&
252+
!range.includeMax &&
253+
range.min != null &&
254+
range.max == range.min.nextBreaking) {
255+
return withConstraint(new VersionConstraint.compatibleWith(range.min));
256+
} else {
257+
return this;
258+
}
259+
}
260+
245261
/// Whether [id] satisfies this dependency.
246262
///
247263
/// Specifically, whether [id] refers to the same package as [this] *and*

lib/src/solver/dependency.dart

-18
This file was deleted.

lib/src/solver/failure.dart

+10-188
Original file line numberDiff line numberDiff line change
@@ -2,201 +2,23 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5-
import 'dart:convert';
6-
7-
import 'package:pub_semver/pub_semver.dart';
8-
import 'package:stack_trace/stack_trace.dart';
9-
105
import '../exceptions.dart';
11-
import '../log.dart' as log;
12-
import '../package_name.dart';
13-
import 'dependency.dart';
6+
import 'incompatibility.dart';
147

158
/// Base class for all failures that can occur while trying to resolve versions.
16-
abstract class SolveFailure implements ApplicationException {
17-
/// The name of the package whose version could not be solved.
18-
///
19-
/// Will be `null` if the failure is not specific to one package.
20-
final String package;
21-
22-
/// The known dependencies on [package] at the time of the failure.
9+
class SolveFailure implements ApplicationException {
10+
/// The root incompatibility.
2311
///
24-
/// Will be an empty collection if the failure is not specific to one package.
25-
final Iterable<Dependency> dependencies;
12+
/// This will always indicate that the root package is unselectable. That is,
13+
/// it will have one term, which will be the root package.
14+
final Incompatibility incompatibility;
2615

2716
String get message => toString();
2817

29-
/// A message describing the specific kind of solve failure.
30-
String get _message {
31-
throw new UnimplementedError("Must override _message or toString().");
32-
}
33-
34-
SolveFailure(this.package, Iterable<Dependency> dependencies)
35-
: dependencies = dependencies != null ? dependencies : <Dependency>[];
36-
37-
String toString() {
38-
if (dependencies.isEmpty) return _message;
39-
40-
var buffer = new StringBuffer();
41-
buffer.write("$_message:");
42-
43-
var sorted = dependencies.toList();
44-
sorted.sort((a, b) => a.depender.name.compareTo(b.depender.name));
45-
46-
for (var dep in sorted) {
47-
buffer.writeln();
48-
buffer.write("- ${log.bold(dep.depender.name)}");
49-
if (!dep.depender.isMagic && !dep.depender.isRoot) {
50-
buffer.write(" ${dep.depender.version}");
51-
}
52-
buffer.write(" ${_describeDependency(dep.dep)}");
53-
}
54-
55-
return buffer.toString();
56-
}
57-
58-
/// Describes a dependency's reference in the output message.
59-
///
60-
/// Override this to highlight which aspect of [dep] led to the failure.
61-
String _describeDependency(PackageRange dep) {
62-
var description = "depends on version ${dep.constraint}";
63-
if (dep.features.isNotEmpty) description += " ${dep.featureDescription}";
64-
return description;
18+
SolveFailure(this.incompatibility) {
19+
assert(incompatibility.terms.single.package.isRoot);
6520
}
66-
}
67-
68-
/// Exception thrown when the current SDK's version does not match a package's
69-
/// constraint on it.
70-
class BadSdkVersionException extends SolveFailure {
71-
final String _message;
72-
73-
BadSdkVersionException(String package, String message)
74-
: _message = message,
75-
super(package, null);
76-
}
77-
78-
/// Exception thrown when the [VersionConstraint] used to match a package is
79-
/// valid (i.e. non-empty), but there are no available versions of the package
80-
/// that fit that constraint.
81-
class NoVersionException extends SolveFailure {
82-
final VersionConstraint constraint;
83-
84-
/// The last selected version of the package that failed to meet the new
85-
/// constraint.
86-
///
87-
/// This will be `null` when the failure occurred because there are no
88-
/// versions of the package *at all* that match the constraint. It will be
89-
/// non-`null` when a version was selected, but then the solver tightened a
90-
/// constraint such that that version was no longer allowed.
91-
final Version version;
92-
93-
NoVersionException(String package, this.version, this.constraint,
94-
Iterable<Dependency> dependencies)
95-
: super(package, dependencies);
96-
97-
String get _message {
98-
if (version == null) {
99-
return "Package $package has no versions that match $constraint derived "
100-
"from";
101-
}
102-
103-
return "Package $package $version does not match $constraint derived from";
104-
}
105-
}
106-
107-
// TODO(rnystrom): Report the list of depending packages and their constraints.
108-
/// Exception thrown when the most recent version of [package] must be selected,
109-
/// but doesn't match the [VersionConstraint] imposed on the package.
110-
class CouldNotUpgradeException extends SolveFailure {
111-
final VersionConstraint constraint;
112-
final Version best;
113-
114-
CouldNotUpgradeException(String package, this.constraint, this.best)
115-
: super(package, null);
116-
117-
String get _message =>
118-
"The latest version of $package, $best, does not match $constraint.";
119-
}
120-
121-
/// Exception thrown when the [VersionConstraint] used to match a package is
122-
/// the empty set: in other words, multiple packages depend on it and have
123-
/// conflicting constraints that have no overlap.
124-
class DisjointConstraintException extends SolveFailure {
125-
DisjointConstraintException(String package, Iterable<Dependency> dependencies)
126-
: super(package, dependencies);
127-
128-
String get _message => "Incompatible version constraints on $package";
129-
}
130-
131-
/// Exception thrown when two packages with the same name but different sources
132-
/// are depended upon.
133-
class SourceMismatchException extends SolveFailure {
134-
String get _message => "Incompatible dependencies on $package";
135-
136-
SourceMismatchException(String package, Iterable<Dependency> dependencies)
137-
: super(package, dependencies);
138-
139-
String _describeDependency(PackageRange dep) =>
140-
"depends on it from source ${dep.source}";
141-
}
142-
143-
/// Exception thrown when a dependency on an unknown source name is found.
144-
class UnknownSourceException extends SolveFailure {
145-
UnknownSourceException(String package, Iterable<Dependency> dependencies)
146-
: super(package, dependencies);
147-
148-
String toString() {
149-
var dep = dependencies.single;
150-
return 'Package ${dep.depender.name} depends on ${dep.dep.name} from '
151-
'unknown source "${dep.dep.source}".';
152-
}
153-
}
154-
155-
/// Exception thrown when two packages with the same name and source but
156-
/// different descriptions are depended upon.
157-
class DescriptionMismatchException extends SolveFailure {
158-
String get _message => "Incompatible dependencies on $package";
159-
160-
DescriptionMismatchException(
161-
String package, Iterable<Dependency> dependencies)
162-
: super(package, dependencies);
163-
164-
String _describeDependency(PackageRange dep) {
165-
// TODO(nweiz): Dump descriptions to YAML when that's supported.
166-
return "depends on it with description ${JSON.encode(dep.description)}";
167-
}
168-
}
169-
170-
/// Exception thrown when a dependency could not be found in its source.
171-
///
172-
/// Unlike [PackageNotFoundException], this includes information about the
173-
/// dependent packages requesting the missing one.
174-
class DependencyNotFoundException extends SolveFailure
175-
implements WrappedException {
176-
final PackageNotFoundException innerError;
177-
Chain get innerChain => innerError.innerChain;
178-
179-
String get _message => "${innerError.message}\nDepended on by";
180-
181-
DependencyNotFoundException(
182-
String package, this.innerError, Iterable<Dependency> dependencies)
183-
: super(package, dependencies);
184-
185-
/// The failure isn't because of the version of description of the package,
186-
/// it's the package itself that can't be found, so just show the name and no
187-
/// descriptive details.
188-
String _describeDependency(PackageRange dep) => "";
189-
}
190-
191-
/// An exception thrown when a dependency requires a feature that doesn't exist.
192-
class MissingFeatureException extends SolveFailure {
193-
final Version version;
194-
final String feature;
195-
196-
String get _message =>
197-
"$package $version doesn't have a feature named $feature";
19821

199-
MissingFeatureException(String package, this.version, this.feature,
200-
Iterable<Dependency> dependencies)
201-
: super(package, dependencies);
22+
// TODO(nweiz): Produce a useful error message.
23+
String toString() => "Tough luck, Chuck!";
20224
}

0 commit comments

Comments
 (0)