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

Side by Side Diff: packages/dart_style/benchmark/after.dart.txt

Issue 1400473008: Roll Observatory packages and add a roll script (Closed) Base URL: git@github.com:dart-lang/observatory_pub_packages.git@master
Patch Set: Created 5 years, 2 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
« no previous file with comments | « packages/dart_style/README.md ('k') | packages/dart_style/benchmark/before.dart.txt » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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.solver.backtracking_solver;
6
7 import 'dart:async';
8 import 'dart:collection' show Queue;
9
10 import '../barback.dart' as barback;
11 import '../exceptions.dart';
12 import '../lock_file.dart';
13 import '../log.dart' as log;
14 import '../package.dart';
15 import '../pubspec.dart';
16 import '../sdk.dart' as sdk;
17 import '../source_registry.dart';
18 import '../source/unknown.dart';
19 import '../utils.dart';
20 import '../version.dart';
21 import 'dependency_queue.dart';
22 import 'version_queue.dart';
23 import 'version_solver.dart';
24
25 /// The top-level solver.
26 ///
27 /// Keeps track of the current potential solution, and the other possible
28 /// versions for speculative package selections. Backtracks and advances to the
29 /// next potential solution in the case of a failure.
30 class BacktrackingSolver {
31 final SolveType type;
32 final SourceRegistry sources;
33 final Package root;
34
35 /// The lockfile that was present before solving.
36 final LockFile lockFile;
37
38 final PubspecCache cache;
39
40 /// The set of packages that are being explicitly upgraded.
41 ///
42 /// The solver will only allow the very latest version for each of these
43 /// packages.
44 final _forceLatest = new Set<String>();
45
46 /// The set of packages whose dependecy is being overridden by the root
47 /// package, keyed by the name of the package.
48 ///
49 /// Any dependency on a package that appears in this map will be overriden
50 /// to use the one here.
51 final _overrides = new Map<String, PackageDep>();
52
53 /// The package versions currently selected by the solver, along with the
54 /// versions which are remaining to be tried.
55 ///
56 /// Every time a package is encountered when traversing the dependency graph,
57 /// the solver must select a version for it, sometimes when multiple versions
58 /// are valid. This keeps track of which versions have been selected so far
59 /// and which remain to be tried.
60 ///
61 /// Each entry in the list is a [VersionQueue], which is an ordered queue of
62 /// versions to try for a single package. It maintains the currently selected
63 /// version for that package. When a new dependency is encountered, a queue
64 /// of versions of that dependency is pushed onto the end of the list. A
65 /// queue is removed from the list once it's empty, indicating that none of
66 /// the versions provided a solution.
67 ///
68 /// The solver tries versions in depth-first order, so only the last queue in
69 /// the list will have items removed from it. When a new constraint is placed
70 /// on an already-selected package, and that constraint doesn't match the
71 /// selected version, that will cause the current solution to fail and
72 /// trigger backtracking.
73 final _selected = <VersionQueue>[];
74
75 /// The number of solutions the solver has tried so far.
76 int get attemptedSolutions => _attemptedSolutions;
77 var _attemptedSolutions = 1;
78
79 BacktrackingSolver(SolveType type, SourceRegistry sources, this.root,
80 this.lockFile, List<String> useLatest)
81 : type = type,
82 sources = sources,
83 cache = new PubspecCache(type, sources) {
84 for (var package in useLatest) {
85 _forceLatest.add(package);
86 }
87
88 for (var override in root.dependencyOverrides) {
89 _overrides[override.name] = override;
90 }
91
92 // A deeply nested statement that's hard on the formatter.
93 isTwoWay = !isEvent &&
94 bindings.isWhole &&
95 (isCustomTag ||
96 tag == 'input' && (name == 'value' || name == 'checked') ||
97 tag == 'select' && (name == 'selectedindex' || name == 'value') ||
98 tag == 'textarea' && name == 'value');
99
100 // Even more deeply nested pathological example.
101 if (javaBooleanAnd(
102 javaBooleanAnd(
103 javaBooleanAnd(
104 javaBooleanAnd(
105 javaBooleanAnd(
106 javaBooleanAnd(
107 javaBooleanAnd(javaBooleanAnd(),
108 _isEqualTokens(node.period, toNode.period)),
109 _isEqualNodes(node.name, toNode.name)),
110 _isEqualNodes(node.parameters, toNode.parameters)),
111 _isEqualTokens(node.separator, toNode.separator)),
112 _isEqualNodeLists(node.initializers, toNode.initializers)),
113 _isEqualNodes(
114 node.redirectedConstructor, toNode.redirectedConstructor)),
115 _isEqualNodes(node.body, toNode.body))) {
116 toNode.element = node.element;
117 }
118 }
119
120 /// Run the solver.
121 ///
122 /// Completes with a list of specific package versions if successful or an
123 /// error if it failed to find a solution.
124 Future<SolveResult> solve() {
125 var stopwatch = new Stopwatch();
126
127 _logParameters();
128
129 // Sort the overrides by package name to make sure they're deterministic.
130 var overrides = _overrides.values.toList();
131 overrides.sort((a, b) => a.name.compareTo(b.name));
132
133 return newFuture(() {
134 stopwatch.start();
135
136 // Pre-cache the root package's known pubspec.
137 cache.cache(new PackageId.root(root), root.pubspec);
138
139 _validateSdkConstraint(root.pubspec);
140 return _traverseSolution();
141 }).then((packages) {
142 var pubspecs = new Map.fromIterable(packages,
143 key: (id) => id.name, value: (id) => cache.getCachedPubspec(id));
144
145 return new SolveResult.success(
146 sources,
147 root,
148 lockFile,
149 packages,
150 overrides,
151 pubspecs,
152 _getAvailableVersions(packages),
153 attemptedSolutions);
154 }).catchError((error) {
155 if (error is! SolveFailure) throw error;
156
157 // Wrap a failure in a result so we can attach some other data.
158 return new SolveResult.failure(
159 sources, root, lockFile, overrides, error, attemptedSolutions);
160 }).whenComplete(() {
161 // Gather some solving metrics.
162 var buffer = new StringBuffer();
163 buffer.writeln('${runtimeType} took ${stopwatch.elapsed} seconds.');
164 buffer.writeln(cache.describeResults());
165 log.solver(buffer);
166 });
167 }
168
169 /// Generates a map containing all of the known available versions for each
170 /// package in [packages].
171 ///
172 /// The version list may not always be complete. The the package is the root
173 /// root package, or its a package that we didn't unlock while solving
174 /// because we weren't trying to upgrade it, we will just know the current
175 /// version.
176 Map<String, List<Version>> _getAvailableVersions(List<PackageId> packages) {
177 var availableVersions = new Map<String, List<Version>>();
178 for (var package in packages) {
179 var cached = cache.getCachedVersions(package.toRef());
180 var versions;
181 if (cached != null) {
182 versions = cached.map((id) => id.version).toList();
183 } else {
184 // If the version list was never requested, just use the one known
185 // version.
186 versions = [package.version];
187 }
188
189 availableVersions[package.name] = versions;
190 }
191
192 return availableVersions;
193 }
194
195 /// Adds [versions], which is the list of all allowed versions of a given
196 /// package, to the set of versions to consider for solutions.
197 ///
198 /// The first item in the list will be the currently selected version of that
199 /// package. Subsequent items will be tried if it the current selection fails.
200 /// Returns the first selected version.
201 PackageId select(VersionQueue versions) {
202 _selected.add(versions);
203 logSolve();
204 return versions.current;
205 }
206
207 /// Returns the the currently selected id for the package [name] or `null` if
208 /// no concrete version has been selected for that package yet.
209 PackageId getSelected(String name) {
210 // Always prefer the root package.
211 if (root.name == name) return new PackageId.root(root);
212
213 // Look through the current selections.
214 for (var i = _selected.length - 1; i >= 0; i--) {
215 if (_selected[i].current.name == name) return _selected[i].current;
216 }
217
218 return null;
219 }
220
221 /// Gets the version of [package] currently locked in the lock file.
222 ///
223 /// Returns `null` if it isn't in the lockfile (or has been unlocked).
224 PackageId getLocked(String package) {
225 if (type == SolveType.GET) return lockFile.packages[package];
226
227 // When downgrading, we don't want to force the latest versions of
228 // non-hosted packages, since they don't support multiple versions and thus
229 // can't be downgraded.
230 if (type == SolveType.DOWNGRADE) {
231 var locked = lockFile.packages[package];
232 if (locked != null && !sources[locked.source].hasMultipleVersions) {
233 return locked;
234 }
235 }
236
237 if (_forceLatest.isEmpty || _forceLatest.contains(package)) return null;
238 return lockFile.packages[package];
239 }
240
241 /// Traverses the root package's dependency graph using the current potential
242 /// solution.
243 ///
244 /// If successful, completes to the solution. If not, backtracks to the most
245 /// recently selected version of a package and tries the next version of it.
246 /// If there are no more versions, continues to backtrack to previous
247 /// selections, and so on. If there is nothing left to backtrack to,
248 /// completes to the last failure that occurred.
249 Future<List<PackageId>> _traverseSolution() => resetStack(() {
250 return new Traverser(this).traverse().catchError((error) {
251 if (error is! SolveFailure) throw error;
252
253 return _backtrack(error).then((canTry) {
254 if (canTry) {
255 _attemptedSolutions++;
256 return _traverseSolution();
257 }
258
259 // All out of solutions, so fail.
260 throw error;
261 });
262 });
263 });
264
265 /// Backtracks from the current failed solution and determines the next
266 /// solution to try.
267 ///
268 /// If possible, it will backjump based on the cause of the [failure] to
269 /// minize backtracking. Otherwise, it will simply backtrack to the next
270 /// possible solution.
271 ///
272 /// Returns `true` if there is a new solution to try.
273 Future<bool> _backtrack(SolveFailure failure) {
274 // Bail if there is nothing to backtrack to.
275 if (_selected.isEmpty) return new Future.value(false);
276
277 // Mark any packages that may have led to this failure so that we know to
278 // consider them when backtracking.
279 var dependers = _getTransitiveDependers(failure.package);
280
281 for (var selected in _selected) {
282 if (dependers.contains(selected.current.name)) {
283 selected.fail();
284 }
285 }
286
287 // Advance past the current version of the leaf-most package.
288 advanceVersion() {
289 _backjump(failure);
290 var previous = _selected.last.current;
291 return _selected.last.advance().then((success) {
292 if (success) {
293 logSolve();
294 return true;
295 }
296
297 logSolve('$previous is last version, backtracking');
298
299 // That package has no more versions, so pop it and try the next one.
300 _selected.removeLast();
301 if (_selected.isEmpty) return false;
302
303 // If we got here, the leafmost package was discarded so we need to
304 // advance the next one.
305 return advanceVersion();
306 });
307 }
308
309 return advanceVersion();
310 }
311
312 /// Walks the selected packages from most to least recent to determine which
313 /// ones can be ignored and jumped over by the backtracker.
314 ///
315 /// The only packages we need to backtrack to are ones that led (possibly
316 /// indirectly) to the failure. Everything else can be skipped.
317 void _backjump(SolveFailure failure) {
318 for (var i = _selected.length - 1; i >= 0; i--) {
319 // Each queue will never be empty since it gets discarded by _backtrack()
320 // when that happens.
321 var selected = _selected[i].current;
322
323 // If the failure is a disjoint version range, then no possible versions
324 // for that package can match and there's no reason to try them. Instead,
325 // just backjump past it.
326 if (failure is DisjointConstraintException &&
327 selected.name == failure.package) {
328 logSolve("skipping past disjoint selected ${selected.name}");
329 continue;
330 }
331
332 if (_selected[i].hasFailed) {
333 logSolve('backjump to ${selected.name}');
334 _selected.removeRange(i + 1, _selected.length);
335 return;
336 }
337 }
338
339 // If we got here, we walked the entire list without finding a package that
340 // could lead to another solution, so discard everything. This will happen
341 // if every package that led to the failure has no other versions that it
342 // can try to select.
343 _selected.removeRange(1, _selected.length);
344 }
345
346 /// Gets the set of currently selected packages that depend on [dependency]
347 /// either directly or indirectly.
348 ///
349 /// When backtracking, it's only useful to consider changing the version of
350 /// packages who have a dependency on the failed package that triggered
351 /// backtracking. This is used to determine those packages.
352 ///
353 /// We calculate the full set up front before backtracking because during
354 /// backtracking, we will unselect packages and start to lose this
355 /// information in the middle of the process.
356 ///
357 /// For example, consider dependencies A -> B -> C. We've selected A and B
358 /// then encounter a problem with C. We start backtracking. B has no more
359 /// versions so we discard it and keep backtracking to A. When we get there,
360 /// since we've unselected B, we no longer realize that A had a transitive
361 /// dependency on C. We would end up backjumping over A and failing.
362 ///
363 /// Calculating the dependency set up front before we start backtracking
364 /// solves that.
365 Set<String> _getTransitiveDependers(String dependency) {
366 // Generate a reverse dependency graph. For each package, create edges to
367 // each package that depends on it.
368 var dependers = new Map<String, Set<String>>();
369
370 addDependencies(name, deps) {
371 dependers.putIfAbsent(name, () => new Set<String>());
372 for (var dep in deps) {
373 dependers.putIfAbsent(dep.name, () => new Set<String>()).add(name);
374 }
375 }
376
377 for (var i = 0; i < _selected.length; i++) {
378 var id = _selected[i].current;
379 var pubspec = cache.getCachedPubspec(id);
380 if (pubspec != null) addDependencies(id.name, pubspec.dependencies);
381 }
382
383 // Include the root package's dependencies.
384 addDependencies(root.name, root.immediateDependencies);
385
386 // Now walk the depending graph to see which packages transitively depend
387 // on [dependency].
388 var visited = new Set<String>();
389 walk(String package) {
390 // Don't get stuck in cycles.
391 if (visited.contains(package)) return;
392 visited.add(package);
393 var depender = dependers[package].forEach(walk);
394 }
395
396 walk(dependency);
397 return visited;
398 }
399
400 /// Logs the initial parameters to the solver.
401 void _logParameters() {
402 var buffer = new StringBuffer();
403 buffer.writeln("Solving dependencies:");
404 for (var package in root.dependencies) {
405 buffer.write("- $package");
406 var locked = getLocked(package.name);
407 if (_forceLatest.contains(package.name)) {
408 buffer.write(" (use latest)");
409 } else if (locked != null) {
410 var version = locked.version;
411 buffer.write(" (locked to $version)");
412 }
413 buffer.writeln();
414 }
415 log.solver(buffer.toString().trim());
416 }
417
418 /// Logs [message] in the context of the current selected packages.
419 ///
420 /// If [message] is omitted, just logs a description of leaf-most selection.
421 void logSolve([String message]) {
422 if (message == null) {
423 if (_selected.isEmpty) {
424 message = "* start at root";
425 } else {
426 message = "* select ${_selected.last.current}";
427 }
428 } else {
429 // Otherwise, indent it under the current selected package.
430 message = prefixLines(message);
431 }
432
433 // Indent for the previous selections.
434 var prefix = _selected.skip(1).map((_) => '| ').join();
435 log.solver(prefixLines(message, prefix: prefix));
436 }
437 }
438
439 /// Given the solver's current set of selected package versions, this tries to
440 /// traverse the dependency graph and see if a complete set of valid versions
441 /// has been chosen.
442 ///
443 /// If it reaches a conflict, it fails and stops traversing. If it reaches a
444 /// package that isn't selected, it refines the solution by adding that
445 /// package's set of allowed versions to the solver and then select the best
446 /// one and continuing.
447 class Traverser {
448 final BacktrackingSolver _solver;
449
450 /// The queue of packages left to traverse.
451 ///
452 /// We do a breadth-first traversal using an explicit queue just to avoid the
453 /// code complexity of a recursive asynchronous traversal.
454 final _packages = new Queue<PackageId>();
455
456 /// The packages we have already traversed.
457 ///
458 /// Used to avoid traversing the same package multiple times, and to build
459 /// the complete solution results.
460 final _visited = new Set<PackageId>();
461
462 /// The dependencies visited so far in the traversal.
463 ///
464 /// For each package name (the map key) we track the list of dependencies
465 /// that other packages have placed on it so that we can calculate the
466 /// complete constraint for shared dependencies.
467 final _dependencies = <String, List<Dependency>>{};
468
469 Traverser(this._solver);
470
471 /// Walks the dependency graph starting at the root package and validates
472 /// that each reached package has a valid version selected.
473 Future<List<PackageId>> traverse() {
474 // Start at the root.
475 _packages.add(new PackageId.root(_solver.root));
476 return _traversePackage();
477 }
478
479 /// Traverses the next package in the queue.
480 ///
481 /// Completes to a list of package IDs if the traversal completed
482 /// successfully and found a solution. Completes to an error if the traversal
483 /// failed. Otherwise, recurses to the next package in the queue, etc.
484 Future<List<PackageId>> _traversePackage() {
485 if (_packages.isEmpty) {
486 // We traversed the whole graph. If we got here, we successfully found
487 // a solution.
488 return new Future<List<PackageId>>.value(_visited.toList());
489 }
490
491 var id = _packages.removeFirst();
492
493 // Don't visit the same package twice.
494 if (_visited.contains(id)) {
495 return _traversePackage();
496 }
497 _visited.add(id);
498
499 return _solver.cache.getPubspec(id).then((pubspec) {
500 _validateSdkConstraint(pubspec);
501
502 var deps = pubspec.dependencies.toSet();
503
504 if (id.isRoot) {
505 // Include dev dependencies of the root package.
506 deps.addAll(pubspec.devDependencies);
507
508 // Add all overrides. This ensures a dependency only present as an
509 // override is still included.
510 deps.addAll(_solver._overrides.values);
511 }
512
513 // Replace any overridden dependencies.
514 deps = deps.map((dep) {
515 var override = _solver._overrides[dep.name];
516 if (override != null) return override;
517
518 // Not overridden.
519 return dep;
520 }).toSet();
521
522 // Make sure the package doesn't have any bad dependencies.
523 for (var dep in deps) {
524 if (!dep.isRoot && _solver.sources[dep.source] is UnknownSource) {
525 throw new UnknownSourceException(
526 id.name, [new Dependency(id.name, id.version, dep)]);
527 }
528 }
529
530 return _traverseDeps(id, new DependencyQueue(_solver, deps));
531 }).catchError((error) {
532 if (error is! PackageNotFoundException) throw error;
533
534 // We can only get here if the lockfile refers to a specific package
535 // version that doesn't exist (probably because it was yanked).
536 throw new NoVersionException(id.name, null, id.version, []);
537 });
538 }
539
540 /// Traverses the references that [depender] depends on, stored in [deps].
541 ///
542 /// Desctructively modifies [deps]. Completes to a list of packages if the
543 /// traversal is complete. Completes it to an error if a failure occurred.
544 /// Otherwise, recurses.
545 Future<List<PackageId>> _traverseDeps(
546 PackageId depender, DependencyQueue deps) {
547 // Move onto the next package if we've traversed all of these references.
548 if (deps.isEmpty) return _traversePackage();
549
550 return resetStack(() {
551 return deps.advance().then((dep) {
552 var dependency = new Dependency(depender.name, depender.version, dep);
553 return _registerDependency(dependency).then((_) {
554 if (dep.name == "barback") return _addImplicitDependencies();
555 });
556 }).then((_) => _traverseDeps(depender, deps));
557 });
558 }
559
560 /// Register [dependency]'s constraints on the package it depends on and
561 /// enqueues the package for processing if necessary.
562 Future _registerDependency(Dependency dependency) {
563 return new Future.sync(() {
564 _validateDependency(dependency);
565
566 var dep = dependency.dep;
567 var dependencies = _getDependencies(dep.name);
568 dependencies.add(dependency);
569
570 var constraint = _getConstraint(dep.name);
571
572 // See if it's possible for a package to match that constraint.
573 if (constraint.isEmpty) {
574 var constraints = dependencies
575 .map((dep) => " ${dep.dep.constraint} from ${dep.depender}")
576 .join('\n');
577 _solver.logSolve('disjoint constraints on ${dep.name}:\n$constraints');
578 throw new DisjointConstraintException(dep.name, dependencies);
579 }
580
581 var selected = _validateSelected(dep, constraint);
582 if (selected != null) {
583 // The selected package version is good, so enqueue it to traverse
584 // into it.
585 _packages.add(selected);
586 return null;
587 }
588
589 // We haven't selected a version. Try all of the versions that match
590 // the constraints we currently have for this package.
591 var locked = _getValidLocked(dep.name);
592
593 return VersionQueue.create(locked, () {
594 return _getAllowedVersions(dep);
595 }).then((versions) => _packages.add(_solver.select(versions)));
596 });
597 }
598
599 /// Gets all versions of [dep] that match the current constraints placed on
600 /// it.
601 Future<Iterable<PackageId>> _getAllowedVersions(PackageDep dep) {
602 var constraint = _getConstraint(dep.name);
603 return _solver.cache.getVersions(dep.toRef()).then((versions) {
604 var allowed = versions.where((id) => constraint.allows(id.version));
605
606 if (allowed.isEmpty) {
607 _solver.logSolve('no versions for ${dep.name} match $constraint');
608 throw new NoVersionException(
609 dep.name, null, constraint, _getDependencies(dep.name));
610 }
611
612 // If we're doing an upgrade on this package, only allow the latest
613 // version.
614 if (_solver._forceLatest.contains(dep.name)) allowed = [allowed.first];
615
616 // Remove the locked version, if any, since that was already handled.
617 var locked = _getValidLocked(dep.name);
618 if (locked != null) {
619 allowed = allowed.where((dep) => dep.version != locked.version);
620 }
621
622 return allowed;
623 }).catchError((error, stackTrace) {
624 if (error is PackageNotFoundException) {
625 // Show the user why the package was being requested.
626 throw new DependencyNotFoundException(
627 dep.name, error, _getDependencies(dep.name));
628 }
629
630 throw error;
631 });
632 }
633
634 /// Ensures that dependency [dep] from [depender] is consistent with the
635 /// other dependencies on the same package.
636 ///
637 /// Throws a [SolveFailure] exception if not. Only validates sources and
638 /// descriptions, not the version.
639 void _validateDependency(Dependency dependency) {
640 var dep = dependency.dep;
641
642 // Make sure the dependencies agree on source and description.
643 var required = _getRequired(dep.name);
644 if (required == null) return;
645
646 // Make sure all of the existing sources match the new reference.
647 if (required.dep.source != dep.source) {
648 _solver.logSolve('source mismatch on ${dep.name}: ${required.dep.source} '
649 '!= ${dep.source}');
650 throw new SourceMismatchException(dep.name, [required, dependency]);
651 }
652
653 // Make sure all of the existing descriptions match the new reference.
654 var source = _solver.sources[dep.source];
655 if (!source.descriptionsEqual(dep.description, required.dep.description)) {
656 _solver.logSolve('description mismatch on ${dep.name}: '
657 '${required.dep.description} != ${dep.description}');
658 throw new DescriptionMismatchException(dep.name, [required, dependency]);
659 }
660 }
661
662 /// Validates the currently selected package against the new dependency that
663 /// [dep] and [constraint] place on it.
664 ///
665 /// Returns `null` if there is no currently selected package, throws a
666 /// [SolveFailure] if the new reference it not does not allow the previously
667 /// selected version, or returns the selected package if successful.
668 PackageId _validateSelected(PackageDep dep, VersionConstraint constraint) {
669 var selected = _solver.getSelected(dep.name);
670 if (selected == null) return null;
671
672 // Make sure it meets the constraint.
673 if (!dep.constraint.allows(selected.version)) {
674 _solver.logSolve('selection $selected does not match $constraint');
675 throw new NoVersionException(
676 dep.name, selected.version, constraint, _getDependencies(dep.name));
677 }
678
679 return selected;
680 }
681
682 /// Register pub's implicit dependencies.
683 ///
684 /// Pub has an implicit version constraint on barback and various other
685 /// packages used in barback's plugin isolate.
686 Future _addImplicitDependencies() {
687 /// Ensure we only add the barback dependency once.
688 if (_getDependencies("barback").length != 1) return new Future.value();
689
690 return Future.wait(barback.pubConstraints.keys.map((depName) {
691 var constraint = barback.pubConstraints[depName];
692 _solver
693 .logSolve('add implicit $constraint pub dependency on ' '$depName');
694
695 var override = _solver._overrides[depName];
696
697 // Use the same source and description as the dependency override if one
698 // exists. This is mainly used by the pkgbuild tests, which use dependency
699 // overrides for all repo packages.
700 var pubDep = override == null
701 ? new PackageDep(depName, "hosted", constraint, depName)
702 : override.withConstraint(constraint);
703 return _registerDependency(
704 new Dependency("pub itself", Version.none, pubDep));
705 }));
706 }
707
708 /// Gets the list of dependencies for package [name].
709 ///
710 /// Creates an empty list if needed.
711 List<Dependency> _getDependencies(String name) {
712 return _dependencies.putIfAbsent(name, () => <Dependency>[]);
713 }
714
715 /// Gets a "required" reference to the package [name].
716 ///
717 /// This is the first non-root dependency on that package. All dependencies
718 /// on a package must agree on source and description, except for references
719 /// to the root package. This will return a reference to that "canonical"
720 /// source and description, or `null` if there is no required reference yet.
721 ///
722 /// This is required because you may have a circular dependency back onto the
723 /// root package. That second dependency won't be a root dependency and it's
724 /// *that* one that other dependencies need to agree on. In other words, you
725 /// can have a bunch of dependencies back onto the root package as long as
726 /// they all agree with each other.
727 Dependency _getRequired(String name) {
728 return _getDependencies(name)
729 .firstWhere((dep) => !dep.dep.isRoot, orElse: () => null);
730 }
731
732 /// Gets the combined [VersionConstraint] currently being placed on package
733 /// [name].
734 VersionConstraint _getConstraint(String name) {
735 var constraint = _getDependencies(name)
736 .map((dep) => dep.dep.constraint)
737 .fold(VersionConstraint.any, (a, b) => a.intersect(b));
738
739 return constraint;
740 }
741
742 /// Gets the package [name] that's currently contained in the lockfile if it
743 /// meets [constraint] and has the same source and description as other
744 /// references to that package.
745 ///
746 /// Returns `null` otherwise.
747 PackageId _getValidLocked(String name) {
748 var package = _solver.getLocked(name);
749 if (package == null) return null;
750
751 var constraint = _getConstraint(name);
752 if (!constraint.allows(package.version)) {
753 _solver.logSolve('$package is locked but does not match $constraint');
754 return null;
755 } else {
756 _solver.logSolve('$package is locked');
757 }
758
759 var required = _getRequired(name);
760 if (required != null) {
761 if (package.source != required.dep.source) return null;
762
763 var source = _solver.sources[package.source];
764 if (!source.descriptionsEqual(
765 package.description, required.dep.description)) return null;
766 }
767
768 return package;
769 }
770
771 /// Run the dart2js compiler.
772 Future _doCompilation(Transform transform) {
773 var provider = new _BarbackCompilerProvider(_environment, transform,
774 generateSourceMaps: _generateSourceMaps);
775
776 // Create a "path" to the entrypoint script. The entrypoint may not actually
777 // be on disk, but this gives dart2js a root to resolve relative paths
778 // against.
779 var id = transform.primaryInput.id;
780
781 var entrypoint = _environment.graph.packages[id.package].path(id.path);
782
783 // Should have more sophisticated error-handling here. Need
784 // to report compile errors to the user in an easily visible way. Need to
785 // make sure paths in errors are mapped to the original source path so they
786 // can understand them.
787 return dart.compile(entrypoint, provider,
788 commandLineOptions: _configCommandLineOptions,
789 csp: _configBool('csp'),
790 checked: _configBool('checked'),
791 minify: _configBool('minify',
792 defaultsTo: _settings.mode == BarbackMode.RELEASE),
793 verbose: _configBool('verbose'),
794 environment: _configEnvironment,
795 packageRoot: _environment.rootPackage.path("packages"),
796 analyzeAll: _configBool('analyzeAll'),
797 suppressWarnings: _configBool('suppressWarnings'),
798 suppressHints: _configBool('suppressHints'),
799 suppressPackageWarnings:
800 _configBool('suppressPackageWarnings', defaultsTo: true),
801 terse: _configBool('terse'),
802 includeSourceMapUrls: _settings.mode != BarbackMode.RELEASE);
803 }
804 }
805
806 /// Ensures that if [pubspec] has an SDK constraint, then it is compatible
807 /// with the current SDK.
808 ///
809 /// Throws a [SolveFailure] if not.
810 void _validateSdkConstraint(Pubspec pubspec) {
811 if (pubspec.environment.sdkVersion.allows(sdk.version)) return;
812
813 throw new BadSdkVersionException(
814 pubspec.name,
815 'Package ${pubspec.name} requires SDK version '
816 '${pubspec.environment.sdkVersion} but the current SDK is '
817 '${sdk.version}.');
818 }
OLDNEW
« no previous file with comments | « packages/dart_style/README.md ('k') | packages/dart_style/benchmark/before.dart.txt » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698