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

Side by Side Diff: sdk/lib/_internal/pub/lib/src/validator/dependency.dart

Issue 1165473002: Start pulling pub from its own repo. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Code review changes Created 5 years, 6 months 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
OLDNEW
(Empty)
1 // Copyright (c) 2012, 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.validator.dependency;
6
7 import 'dart:async';
8
9 import 'package:pub_semver/pub_semver.dart';
10
11 import '../entrypoint.dart';
12 import '../log.dart' as log;
13 import '../package.dart';
14 import '../validator.dart';
15
16 /// The range of all pub versions that don't support `^` version constraints.
17 ///
18 /// This is the actual range of pub versions, whereas [_postCaretPubVersions] is
19 /// the nicer-looking range that doesn't include a prerelease tag.
20 final _preCaretPubVersions = new VersionConstraint.parse("<1.8.0-dev.3.0");
21
22 /// The range of all pub versions that do support `^` version constraints.
23 ///
24 /// This is intersected with the user's SDK constraint to provide a suggested
25 /// constraint.
26 final _postCaretPubVersions = new VersionConstraint.parse("^1.8.0");
27
28 /// A validator that validates a package's dependencies.
29 class DependencyValidator extends Validator {
30 /// Whether the SDK constraint guarantees that `^` version constraints are
31 /// safe.
32 bool get _caretAllowed => entrypoint.root.pubspec.environment.sdkVersion
33 .intersect(_preCaretPubVersions).isEmpty;
34
35 DependencyValidator(Entrypoint entrypoint)
36 : super(entrypoint);
37
38 Future validate() async {
39 var caretDeps = [];
40
41 for (var dependency in entrypoint.root.pubspec.dependencies) {
42 if (dependency.source != "hosted") {
43 await _warnAboutSource(dependency);
44 } else if (dependency.constraint.isAny) {
45 _warnAboutNoConstraint(dependency);
46 } else if (dependency.constraint is Version) {
47 _warnAboutSingleVersionConstraint(dependency);
48 } else if (dependency.constraint is VersionRange) {
49 if (dependency.constraint.min == null) {
50 _warnAboutNoConstraintLowerBound(dependency);
51 } else if (dependency.constraint.max == null) {
52 _warnAboutNoConstraintUpperBound(dependency);
53 }
54
55 if (dependency.constraint.toString().startsWith("^")) {
56 caretDeps.add(dependency);
57 }
58 }
59 }
60
61 if (caretDeps.isNotEmpty && !_caretAllowed) {
62 _errorAboutCaretConstraints(caretDeps);
63 }
64 }
65
66 /// Warn that dependencies should use the hosted source.
67 Future _warnAboutSource(PackageDep dep) async {
68 var versions;
69 try {
70 var pubspecs = await entrypoint.cache.sources['hosted']
71 .getVersions(dep.name, dep.name);
72 versions = pubspecs.map((pubspec) => pubspec.version).toList();
73 } catch (error) {
74 versions = [];
75 }
76
77 var constraint;
78 var primary = Version.primary(versions);
79 if (primary != null) {
80 constraint = _constraintForVersion(primary);
81 } else {
82 constraint = dep.constraint.toString();
83 if (!dep.constraint.isAny && dep.constraint is! Version) {
84 constraint = '"$constraint"';
85 }
86 }
87
88 // Path sources are errors. Other sources are just warnings.
89 var messages = warnings;
90 if (dep.source == "path") {
91 messages = errors;
92 }
93
94 messages.add('Don\'t depend on "${dep.name}" from the ${dep.source} '
95 'source. Use the hosted source instead. For example:\n'
96 '\n'
97 'dependencies:\n'
98 ' ${dep.name}: $constraint\n'
99 '\n'
100 'Using the hosted source ensures that everyone can download your '
101 'package\'s dependencies along with your package.');
102 }
103
104 /// Warn that dependencies should have version constraints.
105 void _warnAboutNoConstraint(PackageDep dep) {
106 var message = 'Your dependency on "${dep.name}" should have a version '
107 'constraint.';
108 var locked = entrypoint.lockFile.packages[dep.name];
109 if (locked != null) {
110 message = '$message For example:\n'
111 '\n'
112 'dependencies:\n'
113 ' ${dep.name}: ${_constraintForVersion(locked.version)}\n';
114 }
115 warnings.add("$message\n"
116 'Without a constraint, you\'re promising to support ${log.bold("all")} '
117 'future versions of "${dep.name}".');
118 }
119
120 /// Warn that dependencies should allow more than a single version.
121 void _warnAboutSingleVersionConstraint(PackageDep dep) {
122 warnings.add(
123 'Your dependency on "${dep.name}" should allow more than one version. '
124 'For example:\n'
125 '\n'
126 'dependencies:\n'
127 ' ${dep.name}: ${_constraintForVersion(dep.constraint)}\n'
128 '\n'
129 'Constraints that are too tight will make it difficult for people to '
130 'use your package\n'
131 'along with other packages that also depend on "${dep.name}".');
132 }
133
134 /// Warn that dependencies should have lower bounds on their constraints.
135 void _warnAboutNoConstraintLowerBound(PackageDep dep) {
136 var message = 'Your dependency on "${dep.name}" should have a lower bound.';
137 var locked = entrypoint.lockFile.packages[dep.name];
138 if (locked != null) {
139 var constraint;
140 if (locked.version == (dep.constraint as VersionRange).max) {
141 constraint = _constraintForVersion(locked.version);
142 } else {
143 constraint = '">=${locked.version} ${dep.constraint}"';
144 }
145
146 message = '$message For example:\n'
147 '\n'
148 'dependencies:\n'
149 ' ${dep.name}: $constraint\n';
150 }
151 warnings.add("$message\n"
152 'Without a constraint, you\'re promising to support ${log.bold("all")} '
153 'previous versions of "${dep.name}".');
154 }
155
156 /// Warn that dependencies should have upper bounds on their constraints.
157 void _warnAboutNoConstraintUpperBound(PackageDep dep) {
158 var constraint;
159 if ((dep.constraint as VersionRange).includeMin) {
160 constraint = _constraintForVersion((dep.constraint as VersionRange).min);
161 } else {
162 constraint = '"${dep.constraint} '
163 '<${(dep.constraint as VersionRange).min.nextBreaking}"';
164 }
165
166 warnings.add(
167 'Your dependency on "${dep.name}" should have an upper bound. For '
168 'example:\n'
169 '\n'
170 'dependencies:\n'
171 ' ${dep.name}: $constraint\n'
172 '\n'
173 'Without an upper bound, you\'re promising to support '
174 '${log.bold("all")} future versions of ${dep.name}.');
175 }
176
177 /// Emits an error for any version constraints that use `^` without an
178 /// appropriate SDK constraint.
179 void _errorAboutCaretConstraints(List<PackageDep> caretDeps) {
180 var newSdkConstraint = entrypoint.root.pubspec.environment.sdkVersion
181 .intersect(_postCaretPubVersions);
182
183 if (newSdkConstraint.isEmpty) newSdkConstraint = _postCaretPubVersions;
184
185 var buffer = new StringBuffer(
186 "Older versions of pub don't support ^ version constraints.\n"
187 "Make sure your SDK constraint excludes those old versions:\n"
188 "\n"
189 "environment:\n"
190 " sdk: \"$newSdkConstraint\"\n"
191 "\n");
192
193 if (caretDeps.length == 1) {
194 buffer.writeln("Or use a fully-expanded constraint:");
195 } else {
196 buffer.writeln("Or use fully-expanded constraints:");
197 }
198
199 buffer.writeln();
200 buffer.writeln("dependencies:");
201
202 caretDeps.forEach((dep) {
203 VersionRange constraint = dep.constraint;
204 buffer.writeln(
205 " ${dep.name}: \">=${constraint.min} <${constraint.max}\"");
206 });
207
208 errors.add(buffer.toString().trim());
209 }
210
211 /// Returns the suggested version constraint for a dependency that was tested
212 /// against [version].
213 String _constraintForVersion(Version version) {
214 if (_caretAllowed) return "^$version";
215 return '">=$version <${version.nextBreaking}"';
216 }
217 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698