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

Side by Side Diff: lib/deferred_library_check.dart

Issue 1535893002: Change the deferred library check tool to allow unspecified packages to be in (Closed) Base URL: git@github.com:dart-lang/dart2js_info.git@master
Patch Set: Created 5 years 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
« README.md ('K') | « README.md ('k') | lib/info.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 /// This tool checks that the output from dart2js meets a given specification, 5 /// This tool checks that the output from dart2js meets a given specification,
6 /// given in a YAML file. The format of the YAML file is: 6 /// given in a YAML file. The format of the YAML file is:
7 /// 7 ///
8 /// main: 8 /// main:
9 /// packages: 9 /// include:
10 /// - some_package 10 /// - some_package
11 /// - other_package 11 /// - other_package
12 /// 12 ///
13 /// foo: 13 /// foo:
14 /// packages: 14 /// include:
15 /// - foo 15 /// - foo
Siggi Cherem (dart-lang) 2015/12/18 02:29:41 should we always implicitly include the foo packag
Harry Terkelsen 2015/12/18 21:22:21 What I'm seeing is more like: import 'package:foo
16 /// - bar 16 /// - bar
17 /// 17 ///
18 /// baz: 18 /// baz:
19 /// packages: 19 /// include:
20 /// - baz 20 /// - baz
21 /// - quux 21 /// - quux
22 /// exclude:
23 /// - zardoz
22 /// 24 ///
23 /// The YAML file consists of a list of declarations, one for each deferred 25 /// The YAML file consists of a list of declarations, one for each deferred
24 /// part expected in the output. At least one of these parts must be named 26 /// part expected in the output. At least one of these parts must be named
25 /// "main"; this is the main part that contains the program entrypoint. Each 27 /// "main"; this is the main part that contains the program entrypoint. Each
26 /// top-level part contains a list of package names that are expected to be 28 /// top-level part contains a list of package names that are expected to be
27 /// contained in that part. Any package that is not explicitly listed is 29 /// contained in that part, a list of package names that are expected to be in
28 /// expected to be in the main part. For instance, in the example YAML above 30 /// another part, or both. For instance, in the example YAML above the part
29 /// the part named "baz" is expected to contain the packages "baz" and "quux". 31 /// named "baz" is expected to contain the packages "baz" and "quux" and not to
32 /// contain the package "zardoz".
30 /// 33 ///
31 /// The names for parts given in the specification YAML file (besides "main") 34 /// The names for parts given in the specification YAML file (besides "main")
32 /// are arbitrary and just used for reporting when the output does not meet the 35 /// are the same as the name given to the deferred import in the dart file. For
33 /// specification. 36 /// instance, if you have `import 'package:foo/foo.dart' deferred as foo;` in
Siggi Cherem (dart-lang) 2015/12/18 02:29:41 same here
Harry Terkelsen 2015/12/18 21:22:21 Done.
37 /// your dart file, then the corresponding name in the specification file is
38 /// 'foo'.
34 library dart2js_info.deferred_library_check; 39 library dart2js_info.deferred_library_check;
35 40
36 import 'info.dart'; 41 import 'info.dart';
37 import 'package:quiver/collection.dart'; 42 import 'package:quiver/collection.dart';
38 43
39 List<ManifestComplianceFailure> checkDeferredLibraryManifest( 44 List<ManifestComplianceFailure> checkDeferredLibraryManifest(
40 AllInfo info, Map manifest) { 45 AllInfo info, Map manifest) {
41 // For each part in the manifest, record the expected "packages" for that 46 var includedPackages = new Multimap<String, String>();
42 // part. 47 var excludedPackages = new Multimap<String, String>();
43 var packages = <String, String>{};
44 for (var part in manifest.keys) { 48 for (var part in manifest.keys) {
45 for (var package in manifest[part]['packages']) { 49 for (var package in manifest[part]['include'] ?? []) {
46 if (packages.containsKey(package)) { 50 includedPackages.add(part, package);
47 throw new ArgumentError.value( 51 }
48 manifest, 52 for (var package in manifest[part]['exclude'] ?? []) {
49 'manifest', 53 excludedPackages.add(part, package);
50 'You cannot specify that package "$package" maps to both parts '
51 '"$part" and "${packages[package]}".');
52 }
53 packages[package] = part;
54 } 54 }
55 } 55 }
56 56
57 var guessedPartMapping = new BiMap<String, String>(); 57 // There are 2 types of parts that are valid to mention in the specification
58 guessedPartMapping['main'] = 'main'; 58 // file. These are the main part and directly imported deferred parts. The
59 // main part is always named 'main'; the directly imported deferred parts are
60 // the outputUnits whose list of 'imports' contains a single import. If the
61 // part is shared, it will have more than one import since it will include the
62 // imports of all the top-level deferred parts that will load the shared part.
63 List<String> validParts = ['main']
Siggi Cherem (dart-lang) 2015/12/18 02:29:41 we might want to validate that there are no 2 part
Harry Terkelsen 2015/12/18 21:22:21 Do you still think we should do this since the nam
Siggi Cherem (dart-lang) 2015/12/18 21:34:25 Good point - nope, it makes sense to leave it as i
64 ..addAll(info.outputUnits
65 .where((unit) => unit.imports.length == 1)
66 .map((unit) => unit.imports.single));
Siggi Cherem (dart-lang) 2015/12/18 02:29:41 do we need to get the package name from the librar
Harry Terkelsen 2015/12/18 21:22:21 unit.imports is a list of the names of the deferre
Siggi Cherem (dart-lang) 2015/12/18 21:34:25 interesting - I really thought that these were the
Harry Terkelsen 2015/12/18 21:42:53 I think if there are two with the same name then o
67 List<String> mentionedParts = []
68 ..addAll(includedPackages.keys)
69 ..addAll(excludedPackages.keys);
70 var partNameFailures = <_InvalidPartName>[];
71 for (var part in mentionedParts) {
72 if (!validParts.contains(part)) {
73 partNameFailures.add(new _InvalidPartName(part, validParts));
74 }
75 }
76 if (partNameFailures.isNotEmpty) {
77 return partNameFailures;
78 }
79
80 var mentionedPackages = new Set()
81 ..addAll(includedPackages.values)
82 ..addAll(excludedPackages.values);
83 var actualIncludedPackages = new Multimap<String, String>();
59 84
60 var failures = <ManifestComplianceFailure>[]; 85 var failures = <ManifestComplianceFailure>[];
61 86
62 checkInfo(BasicInfo info) { 87 checkInfo(BasicInfo info) {
88 if (info.size == 0) return;
63 var lib = _getLibraryOf(info); 89 var lib = _getLibraryOf(info);
64 if (lib != null && _isPackageUri(lib.uri)) { 90 if (lib != null && _isPackageUri(lib.uri)) {
65 var packageName = _getPackageName(lib.uri); 91 var packageName = _getPackageName(lib.uri);
66 var outputUnitName = info.outputUnit.name; 92 if (!mentionedPackages.contains(packageName)) return;
67 var expectedPart; 93 var containingParts = <String>[];
68 if (packages.containsKey(packageName)) { 94 if (info.outputUnit.name == 'main') {
69 expectedPart = packages[packageName]; 95 containingParts.add('main');
70 } else { 96 } else {
71 expectedPart = 'main'; 97 containingParts.addAll(info.outputUnit.imports);
72 } 98 }
73 var expectedOutputUnit = guessedPartMapping[expectedPart]; 99 for (var part in containingParts) {
74 if (expectedOutputUnit == null) { 100 actualIncludedPackages.add(part, packageName);
75 guessedPartMapping[expectedPart] = outputUnitName; 101 if (excludedPackages[part].contains(packageName)) {
76 } else { 102 failures
77 if (expectedOutputUnit != outputUnitName) { 103 .add(new _PartContainedExcludedPackage(part, packageName, info));
78 // TODO(het): add options for how to treat unspecified packages
79 if (!packages.containsKey(packageName)) {
80 failures.add(new ManifestComplianceFailure(info.name, packageName));
81 } else {
82 var actualPart = guessedPartMapping.inverse[outputUnitName];
83 failures.add(new ManifestComplianceFailure(
84 info.name, packageName, expectedPart, actualPart));
85 }
86 } 104 }
87 } 105 }
88 } 106 }
89 } 107 }
90 108
91 info.functions.forEach(checkInfo); 109 info.functions.forEach(checkInfo);
92 info.fields.forEach(checkInfo); 110 info.fields.forEach(checkInfo);
93 111
112 includedPackages.forEach((part, package) {
113 if (!actualIncludedPackages.containsKey(part) ||
114 !actualIncludedPackages[part].contains(package)) {
115 failures.add(new _PartDidNotContainPackage(part, package));
116 }
117 });
94 return failures; 118 return failures;
95 } 119 }
96 120
97 LibraryInfo _getLibraryOf(Info info) { 121 LibraryInfo _getLibraryOf(Info info) {
98 var current = info; 122 var current = info;
99 while (current is! LibraryInfo) { 123 while (current is! LibraryInfo) {
100 if (current == null) { 124 if (current == null) {
101 return null; 125 return null;
102 } 126 }
103 current = current.parent; 127 current = current.parent;
104 } 128 }
105 return current; 129 return current;
106 } 130 }
107 131
108 bool _isPackageUri(Uri uri) => uri.scheme == 'package'; 132 bool _isPackageUri(Uri uri) => uri.scheme == 'package';
109 133
110 String _getPackageName(Uri uri) { 134 String _getPackageName(Uri uri) {
111 assert(_isPackageUri(uri)); 135 assert(_isPackageUri(uri));
112 return uri.pathSegments.first; 136 return uri.pathSegments.first;
113 } 137 }
114 138
115 class ManifestComplianceFailure { 139 class ManifestComplianceFailure {
116 final String infoName; 140 const ManifestComplianceFailure();
117 final String packageName; 141 }
118 final String expectedPart;
119 final String actualPart;
120 142
121 const ManifestComplianceFailure(this.infoName, this.packageName, 143 class _InvalidPartName extends ManifestComplianceFailure {
122 [this.expectedPart, this.actualPart]); 144 final String part;
145 final List<String> validPartNames;
146 const _InvalidPartName(this.part, this.validPartNames);
123 147
124 String toString() { 148 String toString() {
125 if (expectedPart == null && actualPart == null) { 149 return 'Manifest file declares invalid part "$part". '
126 return '"$infoName" from package "$packageName" was not declared ' 150 'Valid part names are: $validPartNames';
127 'to be in an explicit part but was not in the main part';
128 } else {
129 return '"$infoName" from package "$packageName" was specified to '
130 'be in part $expectedPart but is in part $actualPart';
131 }
132 } 151 }
133 } 152 }
153
154 class _PartContainedExcludedPackage extends ManifestComplianceFailure {
155 final String part;
156 final String package;
157 final BasicInfo info;
158 const _PartContainedExcludedPackage(this.part, this.package, this.info);
159
160 String toString() {
161 return 'Part "$part" was specified to exclude package "$package" but it '
162 'actually contains ${kindToString(info.kind)} "${info.name}" which '
163 'is from package "$package"';
164 }
165 }
166
167 class _PartDidNotContainPackage extends ManifestComplianceFailure {
168 final String part;
169 final String package;
170 const _PartDidNotContainPackage(this.part, this.package);
171
172 String toString() {
173 return 'Part "$part" was specified to include package "$package" but it '
174 'does not contain any elements from that package.';
175 }
176 }
OLDNEW
« README.md ('K') | « README.md ('k') | lib/info.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698