OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'dart:async'; | 5 import 'dart:async'; |
6 | 6 |
7 import 'package:pub/src/lock_file.dart'; | 7 import 'package:pub/src/lock_file.dart'; |
8 import 'package:pub/src/log.dart' as log; | 8 import 'package:pub/src/log.dart' as log; |
9 import 'package:pub/src/package.dart'; | 9 import 'package:pub/src/package.dart'; |
10 import 'package:pub/src/pubspec.dart'; | 10 import 'package:pub/src/pubspec.dart'; |
11 import 'package:pub/src/sdk.dart' as sdk; | 11 import 'package:pub/src/sdk.dart' as sdk; |
12 import 'package:pub/src/solver/version_solver.dart'; | 12 import 'package:pub/src/solver/version_solver.dart'; |
13 import 'package:pub/src/source.dart'; | 13 import 'package:pub/src/source.dart'; |
14 import 'package:pub/src/source/cached.dart'; | 14 import 'package:pub/src/source/cached.dart'; |
15 import 'package:pub/src/source_registry.dart'; | |
15 import 'package:pub/src/system_cache.dart'; | 16 import 'package:pub/src/system_cache.dart'; |
16 import 'package:pub/src/utils.dart'; | 17 import 'package:pub/src/utils.dart'; |
17 import 'package:pub_semver/pub_semver.dart'; | 18 import 'package:pub_semver/pub_semver.dart'; |
18 import 'package:test/test.dart'; | 19 import 'package:test/test.dart'; |
19 | 20 |
20 MockSource source1; | 21 MockSource source1; |
21 MockSource source2; | 22 MockSource source2; |
22 | 23 |
23 main() { | 24 main() { |
24 // Uncomment this to debug failing tests. | 25 // Uncomment this to debug failing tests. |
(...skipping 620 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
645 'b 2.0.0': { | 646 'b 2.0.0': { |
646 'a-y': 'any' | 647 'a-y': 'any' |
647 }, | 648 }, |
648 'c 1.0.0': {}, | 649 'c 1.0.0': {}, |
649 'c 2.0.0': {}, | 650 'c 2.0.0': {}, |
650 'c 3.0.0': {}, | 651 'c 3.0.0': {}, |
651 'c 4.0.0': {}, | 652 'c 4.0.0': {}, |
652 'c 5.0.0': {}, | 653 'c 5.0.0': {}, |
653 }, result: { | 654 }, result: { |
654 'myapp from root': '0.0.0', | 655 'myapp from root': '0.0.0', |
655 'a': '1.0.0', | 656 'a-x': '1.0.0', |
Bob Nystrom
2016/06/23 20:29:49
Why the change here?
nweiz
2016/06/23 21:01:21
Previously, the result wasn't validating which "a
Bob Nystrom
2016/06/23 22:02:20
Ah, cool. I thought it was actually producing a di
| |
656 'b': '1.0.0', | 657 'b': '1.0.0', |
657 'c': '5.0.0' | 658 'c': '5.0.0' |
658 }, maxTries: 2); | 659 }, maxTries: 2); |
659 | 660 |
660 // Similar to the above two tests but where there is no solution. It should | 661 // Similar to the above two tests but where there is no solution. It should |
661 // fail in this case with no backtracking. | 662 // fail in this case with no backtracking. |
662 testResolve('backjump to conflicting source', { | 663 testResolve('backjump to conflicting source', { |
663 'myapp 0.0.0': { | 664 'myapp 0.0.0': { |
664 'a': 'any', | 665 'a': 'any', |
665 'b': 'any', | 666 'b': 'any', |
(...skipping 448 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1114 source2 = new MockSource('mock2'); | 1115 source2 = new MockSource('mock2'); |
1115 | 1116 |
1116 var cache = new SystemCache(rootDir: '.'); | 1117 var cache = new SystemCache(rootDir: '.'); |
1117 cache.sources.register(source1); | 1118 cache.sources.register(source1); |
1118 cache.sources.register(source2); | 1119 cache.sources.register(source2); |
1119 cache.sources.setDefault(source1.name); | 1120 cache.sources.setDefault(source1.name); |
1120 | 1121 |
1121 // Build the test package graph. | 1122 // Build the test package graph. |
1122 var root; | 1123 var root; |
1123 packages.forEach((description, dependencies) { | 1124 packages.forEach((description, dependencies) { |
1124 var id = parseSpec(description); | 1125 var id = parseSpec(cache.sources, description); |
1125 var package = mockPackage(id, dependencies, | 1126 var package = mockPackage(cache.sources, id, dependencies, |
1126 id.name == 'myapp' ? overrides : null); | 1127 id.name == 'myapp' ? overrides : null); |
1127 if (id.name == 'myapp') { | 1128 if (id.name == 'myapp') { |
1128 // Don't add the root package to the server, so we can verify that Pub | 1129 // Don't add the root package to the server, so we can verify that Pub |
1129 // doesn't try to look up information about the local package on the | 1130 // doesn't try to look up information about the local package on the |
1130 // remote server. | 1131 // remote server. |
1131 root = package; | 1132 root = package; |
1132 } else { | 1133 } else { |
1133 (cache.source(id.source) as BoundMockSource) | 1134 (cache.source(id.source) as BoundMockSource) |
1134 .addPackage(id.description, package); | 1135 .addPackage(id.description, package); |
1135 } | 1136 } |
1136 }); | 1137 }); |
1137 | 1138 |
1138 // Clean up the expectation. | 1139 // Clean up the expectation. |
1139 if (result != null) { | 1140 if (result != null) { |
1140 var newResult = {}; | 1141 var newResult = {}; |
1141 result.forEach((description, version) { | 1142 result.forEach((description, version) { |
1142 var id = parseSpec(description, version); | 1143 var id = parseSpec(cache.sources, description, version); |
1143 newResult[id.name] = id; | 1144 newResult[id.name] = id; |
1144 }); | 1145 }); |
1145 result = newResult; | 1146 result = newResult; |
1146 } | 1147 } |
1147 | 1148 |
1148 // Parse the lockfile. | 1149 // Parse the lockfile. |
1149 var realLockFile; | 1150 var realLockFile; |
1150 if (lockfile == null) { | 1151 if (lockfile == null) { |
1151 realLockFile = new LockFile.empty(cache.sources); | 1152 realLockFile = new LockFile.empty(); |
1152 } else { | 1153 } else { |
1153 realLockFile = new LockFile(lockfile.keys.map((name) { | 1154 realLockFile = new LockFile(lockfile.keys.map((name) { |
1154 var version = new Version.parse(lockfile[name]); | 1155 var version = new Version.parse(lockfile[name]); |
1155 return new PackageId(name, source1.name, version, name); | 1156 return new PackageId(name, source1, version, name); |
1156 }), cache.sources); | 1157 })); |
1157 } | 1158 } |
1158 | 1159 |
1159 // Resolve the versions. | 1160 // Resolve the versions. |
1160 log.verbosity = log.Verbosity.NONE; | 1161 log.verbosity = log.Verbosity.NONE; |
1161 var future = resolveVersions( | 1162 var future = resolveVersions( |
1162 downgrade ? SolveType.DOWNGRADE : SolveType.GET, | 1163 downgrade ? SolveType.DOWNGRADE : SolveType.GET, |
1163 cache, root, lockFile: realLockFile); | 1164 cache, root, lockFile: realLockFile); |
1164 | 1165 |
1165 var matcher; | 1166 var matcher; |
1166 if (result != null) { | 1167 if (result != null) { |
(...skipping 184 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1351 /// characters. | 1352 /// characters. |
1352 class MockSource extends Source { | 1353 class MockSource extends Source { |
1353 final String name; | 1354 final String name; |
1354 final hasMultipleVersions = true; | 1355 final hasMultipleVersions = true; |
1355 | 1356 |
1356 MockSource(this.name); | 1357 MockSource(this.name); |
1357 | 1358 |
1358 BoundSource bind(SystemCache cache) => new BoundMockSource(this, cache); | 1359 BoundSource bind(SystemCache cache) => new BoundMockSource(this, cache); |
1359 | 1360 |
1360 PackageRef parseRef(String name, description, {String containingPath}) => | 1361 PackageRef parseRef(String name, description, {String containingPath}) => |
1361 new PackageRef(name, this.name, description); | 1362 new PackageRef(name, this, description); |
1362 | 1363 |
1363 PackageId parseId(String name, Version version, description) => | 1364 PackageId parseId(String name, Version version, description) => |
1364 new PackageId(name, this.name, version, description); | 1365 new PackageId(name, this, version, description); |
1365 | 1366 |
1366 bool descriptionsEqual(description1, description2) => | 1367 bool descriptionsEqual(description1, description2) => |
1367 description1 == description2; | 1368 description1 == description2; |
1369 | |
1370 int hashDescription(description) => description.hashCode; | |
1368 } | 1371 } |
1369 | 1372 |
1370 class BoundMockSource extends CachedSource { | 1373 class BoundMockSource extends CachedSource { |
1371 final SystemCache systemCache; | 1374 final SystemCache systemCache; |
1372 | 1375 |
1373 final MockSource source; | 1376 final MockSource source; |
1374 | 1377 |
1375 final _packages = <String, Map<Version, Package>>{}; | 1378 final _packages = <String, Map<Version, Package>>{}; |
1376 | 1379 |
1377 /// Keeps track of which package version lists have been requested. Ensures | 1380 /// Keeps track of which package version lists have been requested. Ensures |
(...skipping 18 matching lines...) Expand all Loading... | |
1396 } | 1399 } |
1397 | 1400 |
1398 _requestedVersions.add(ref.description); | 1401 _requestedVersions.add(ref.description); |
1399 | 1402 |
1400 if (!_packages.containsKey(ref.description)){ | 1403 if (!_packages.containsKey(ref.description)){ |
1401 throw new Exception('MockSource does not have a package matching ' | 1404 throw new Exception('MockSource does not have a package matching ' |
1402 '"${ref.description}".'); | 1405 '"${ref.description}".'); |
1403 } | 1406 } |
1404 | 1407 |
1405 return _packages[ref.description].values.map((package) { | 1408 return _packages[ref.description].values.map((package) { |
1406 return new PackageId( | 1409 return new PackageId(ref.name, source, package.version, ref.description); |
1407 ref.name, source.name, package.version, ref.description); | |
1408 }).toList(); | 1410 }).toList(); |
1409 } | 1411 } |
1410 | 1412 |
1411 Future<Pubspec> describeUncached(PackageId id) { | 1413 Future<Pubspec> describeUncached(PackageId id) { |
1412 return new Future.sync(() { | 1414 return new Future.sync(() { |
1413 // Make sure the solver doesn't request the same thing twice. | 1415 // Make sure the solver doesn't request the same thing twice. |
1414 if (_requestedPubspecs.containsKey(id.description) && | 1416 if (_requestedPubspecs.containsKey(id.description) && |
1415 _requestedPubspecs[id.description].contains(id.version)) { | 1417 _requestedPubspecs[id.description].contains(id.version)) { |
1416 throw new Exception('Pubspec for $id was already requested.'); | 1418 throw new Exception('Pubspec for $id was already requested.'); |
1417 } | 1419 } |
(...skipping 13 matching lines...) Expand all Loading... | |
1431 | 1433 |
1432 Future<Pair<List<PackageId>, List<PackageId>>> repairCachedPackages() => | 1434 Future<Pair<List<PackageId>, List<PackageId>>> repairCachedPackages() => |
1433 throw new UnsupportedError('Cannot repair mock packages'); | 1435 throw new UnsupportedError('Cannot repair mock packages'); |
1434 | 1436 |
1435 void addPackage(String description, Package package) { | 1437 void addPackage(String description, Package package) { |
1436 _packages.putIfAbsent(description, () => new Map<Version, Package>()); | 1438 _packages.putIfAbsent(description, () => new Map<Version, Package>()); |
1437 _packages[description][package.version] = package; | 1439 _packages[description][package.version] = package; |
1438 } | 1440 } |
1439 } | 1441 } |
1440 | 1442 |
1441 Package mockPackage(PackageId id, Map dependencyStrings, Map overrides) { | 1443 Package mockPackage(SourceRegistry sources, PackageId id, Map dependencyStrings, |
1444 Map overrides) { | |
1442 var sdkConstraint = null; | 1445 var sdkConstraint = null; |
1443 | 1446 |
1444 // Build the pubspec dependencies. | 1447 // Build the pubspec dependencies. |
1445 var dependencies = <PackageDep>[]; | 1448 var dependencies = <PackageDep>[]; |
1446 var devDependencies = <PackageDep>[]; | 1449 var devDependencies = <PackageDep>[]; |
1447 | 1450 |
1448 dependencyStrings.forEach((spec, constraint) { | 1451 dependencyStrings.forEach((spec, constraint) { |
1449 var isDev = spec.startsWith("(dev) "); | 1452 var isDev = spec.startsWith("(dev) "); |
1450 if (isDev) { | 1453 if (isDev) { |
1451 spec = spec.substring("(dev) ".length); | 1454 spec = spec.substring("(dev) ".length); |
1452 } | 1455 } |
1453 | 1456 |
1454 var dep = parseSpec(spec).withConstraint( | 1457 var dep = parseSpec(sources, spec).withConstraint( |
1455 new VersionConstraint.parse(constraint)); | 1458 new VersionConstraint.parse(constraint)); |
1456 | 1459 |
1457 if (dep.name == 'sdk') { | 1460 if (dep.name == 'sdk') { |
1458 sdkConstraint = dep.constraint; | 1461 sdkConstraint = dep.constraint; |
1459 return; | 1462 return; |
1460 } | 1463 } |
1461 | 1464 |
1462 if (isDev) { | 1465 if (isDev) { |
1463 devDependencies.add(dep); | 1466 devDependencies.add(dep); |
1464 } else { | 1467 } else { |
1465 dependencies.add(dep); | 1468 dependencies.add(dep); |
1466 } | 1469 } |
1467 }); | 1470 }); |
1468 | 1471 |
1469 var dependencyOverrides = <PackageDep>[]; | 1472 var dependencyOverrides = <PackageDep>[]; |
1470 if (overrides != null) { | 1473 if (overrides != null) { |
1471 overrides.forEach((spec, constraint) { | 1474 overrides.forEach((spec, constraint) { |
1472 dependencyOverrides.add(parseSpec(spec).withConstraint( | 1475 dependencyOverrides.add(parseSpec(sources, spec) |
1473 new VersionConstraint.parse(constraint))); | 1476 .withConstraint(new VersionConstraint.parse(constraint))); |
1474 }); | 1477 }); |
1475 } | 1478 } |
1476 | 1479 |
1477 return new Package.inMemory(new Pubspec(id.name, | 1480 return new Package.inMemory(new Pubspec(id.name, |
1478 version: id.version, | 1481 version: id.version, |
1479 dependencies: dependencies, | 1482 dependencies: dependencies, |
1480 devDependencies: devDependencies, | 1483 devDependencies: devDependencies, |
1481 dependencyOverrides: dependencyOverrides, | 1484 dependencyOverrides: dependencyOverrides, |
1482 sdkConstraint: sdkConstraint)); | 1485 sdkConstraint: sdkConstraint)); |
1483 } | 1486 } |
1484 | 1487 |
1485 /// Creates a new [PackageId] parsed from [text], which looks something like | 1488 /// Creates a new [PackageId] parsed from [text], which looks something like |
1486 /// this: | 1489 /// this: |
1487 /// | 1490 /// |
1488 /// foo-xyz 1.0.0 from mock | 1491 /// foo-xyz 1.0.0 from mock |
1489 /// | 1492 /// |
1490 /// The package name is "foo". A hyphenated suffix like "-xyz" here is part | 1493 /// The package name is "foo". A hyphenated suffix like "-xyz" here is part |
1491 /// of the package description, but not its name, so the description here is | 1494 /// of the package description, but not its name, so the description here is |
1492 /// "foo-xyz". | 1495 /// "foo-xyz". |
1493 /// | 1496 /// |
1494 /// This is followed by an optional [Version]. If [version] is provided, then | 1497 /// This is followed by an optional [Version]. If [version] is provided, then |
1495 /// it is parsed to a [Version], and [text] should *not* also contain a | 1498 /// it is parsed to a [Version], and [text] should *not* also contain a |
1496 /// version string. | 1499 /// version string. |
1497 /// | 1500 /// |
1498 /// The "from mock" optional suffix is the name of a source for the package. | 1501 /// The "from mock" optional suffix is the name of a source for the package. |
1499 /// If omitted, it defaults to "mock1". | 1502 /// If omitted, it defaults to "mock1". |
1500 PackageId parseSpec(String text, [String version]) { | 1503 PackageId parseSpec(SourceRegistry sources, String text, [String version]) { |
1501 var pattern = new RegExp(r"(([a-z_]*)(-[a-z_]+)?)( ([^ ]+))?( from (.*))?$"); | 1504 var pattern = new RegExp(r"(([a-z_]*)(-[a-z_]+)?)( ([^ ]+))?( from (.*))?$"); |
1502 var match = pattern.firstMatch(text); | 1505 var match = pattern.firstMatch(text); |
1503 if (match == null) { | 1506 if (match == null) { |
1504 throw new FormatException("Could not parse spec '$text'."); | 1507 throw new FormatException("Could not parse spec '$text'."); |
1505 } | 1508 } |
1506 | 1509 |
1507 var description = match[1]; | 1510 var description = match[1]; |
1508 var name = match[2]; | 1511 var name = match[2]; |
1509 | 1512 |
1510 var parsedVersion; | 1513 var parsedVersion; |
1511 if (version != null) { | 1514 if (version != null) { |
1512 // Spec string shouldn't also contain a version. | 1515 // Spec string shouldn't also contain a version. |
1513 if (match[5] != null) { | 1516 if (match[5] != null) { |
1514 throw new ArgumentError("Spec '$text' should not contain a version " | 1517 throw new ArgumentError("Spec '$text' should not contain a version " |
1515 "since '$version' was passed in explicitly."); | 1518 "since '$version' was passed in explicitly."); |
1516 } | 1519 } |
1517 parsedVersion = new Version.parse(version); | 1520 parsedVersion = new Version.parse(version); |
1518 } else { | 1521 } else { |
1519 if (match[5] != null) { | 1522 if (match[5] != null) { |
1520 parsedVersion = new Version.parse(match[5]); | 1523 parsedVersion = new Version.parse(match[5]); |
1521 } else { | 1524 } else { |
1522 parsedVersion = Version.none; | 1525 parsedVersion = Version.none; |
1523 } | 1526 } |
1524 } | 1527 } |
1525 | 1528 |
1526 var source = "mock1"; | 1529 var source = sources["mock1"]; |
1527 if (match[7] != null) { | 1530 if (match[7] != null) source = match[7] == "root" ? null : sources[match[7]]; |
1528 source = match[7]; | |
1529 if (source == "root") source = null; | |
1530 } | |
1531 | 1531 |
1532 return new PackageId(name, source, parsedVersion, description); | 1532 return new PackageId(name, source, parsedVersion, description); |
1533 } | 1533 } |
OLD | NEW |