Skip to content

Commit bd28bad

Browse files
vsmenoncommit-bot@chromium.org
authored andcommitted
[dartdevc] add modular tests for old ddc
Change-Id: Iff068cc4e737e9a6993c6f724fc0b6853ed1d5fc Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/113621 Reviewed-by: Sigmund Cherem <[email protected]> Commit-Queue: Vijay Menon <[email protected]>
1 parent 9f4f0ac commit bd28bad

File tree

3 files changed

+333
-1
lines changed

3 files changed

+333
-1
lines changed
Lines changed: 315 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,315 @@
1+
// Copyright (c) 2019, 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+
/// Test the modular compilation pipeline of ddc.
6+
///
7+
/// This is a shell that runs multiple tests, one per folder under `data/`.
8+
import 'dart:io';
9+
10+
import 'package:modular_test/src/io_pipeline.dart';
11+
import 'package:modular_test/src/pipeline.dart';
12+
import 'package:modular_test/src/suite.dart';
13+
import 'package:modular_test/src/runner.dart';
14+
15+
// TODO(vsm): Hack until we have either:
16+
// (1) an NNBD version of the below
17+
// (2) the ability to compile the primary version with NNBD
18+
List<String> _nnbdOptOut = [];
19+
String _test_package = 'ddc_modular_test';
20+
21+
Uri sdkRoot = Platform.script.resolve("../../../");
22+
Options _options;
23+
String _dartdevcScript;
24+
String _buildSdkScript;
25+
String _patchSdkScript;
26+
String _sdkDevRuntime;
27+
28+
main(List<String> args) async {
29+
_options = Options.parse(args);
30+
await _resolveScripts();
31+
await runSuite(
32+
sdkRoot.resolve('tests/modular/'),
33+
'tests/modular',
34+
_options,
35+
IOPipeline([
36+
DDCStep(),
37+
RunD8(),
38+
], cacheSharedModules: true, saveIntermediateResultsForTesting: false));
39+
}
40+
41+
const sumId = DataId("sum");
42+
const jsId = DataId("js");
43+
const txtId = DataId("txt");
44+
45+
class DDCStep implements IOModularStep {
46+
@override
47+
List<DataId> get resultData => const [sumId, jsId];
48+
49+
@override
50+
bool get needsSources => true;
51+
52+
@override
53+
List<DataId> get dependencyDataNeeded => const [sumId];
54+
55+
@override
56+
List<DataId> get moduleDataNeeded => const [];
57+
58+
@override
59+
bool get onlyOnMain => false;
60+
61+
@override
62+
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
63+
List<String> flags) async {
64+
if (_options.verbose) print("\nstep: ddc on $module");
65+
66+
Set<Module> transitiveDependencies = computeTransitiveDependencies(module);
67+
await _createPackagesFile(module, root, transitiveDependencies);
68+
69+
ProcessResult result;
70+
71+
bool nnbd = flags.contains('non-nullable');
72+
if (nnbd && _nnbdOptOut.contains(module.name)) {
73+
flags = List.from(flags);
74+
flags.remove('non-nullable');
75+
}
76+
77+
if (module.isSdk) {
78+
assert(transitiveDependencies.isEmpty);
79+
80+
// Apply patches.
81+
result = await _runProcess(
82+
Platform.resolvedExecutable,
83+
[
84+
_patchSdkScript,
85+
sdkRoot.toFilePath(),
86+
_sdkDevRuntime,
87+
'patched_sdk',
88+
if (nnbd) 'sdk_nnbd'
89+
],
90+
root.toFilePath());
91+
_checkExitCode(result, this, module);
92+
93+
// Build the SDK.
94+
result = await _runProcess(
95+
Platform.resolvedExecutable,
96+
[
97+
_buildSdkScript,
98+
'--dart-sdk',
99+
'patched_sdk',
100+
'--dart-sdk-summary=build',
101+
'--summary-out',
102+
'${toUri(module, sumId)}',
103+
'--modules=es6',
104+
for (String flag in flags) '--enable-experiment=$flag',
105+
'-o',
106+
'${toUri(module, jsId)}',
107+
],
108+
root.toFilePath());
109+
_checkExitCode(result, this, module);
110+
} else {
111+
Module sdkModule = module.dependencies.firstWhere((m) => m.isSdk);
112+
List<String> sources = module.sources
113+
.map((relativeUri) => _sourceToImportUri(module, relativeUri))
114+
.toList();
115+
Map<String, String> _urlMappings = {};
116+
if (!module.isPackage) {
117+
for (var source in module.sources) {
118+
var importUri = _sourceToImportUri(module, source);
119+
_urlMappings[importUri] = '$source';
120+
}
121+
}
122+
for (var dependency in transitiveDependencies) {
123+
if (!dependency.isPackage && !dependency.isSdk) {
124+
for (var source in dependency.sources) {
125+
var importUri = _sourceToImportUri(dependency, source);
126+
_urlMappings[importUri] = '$source';
127+
}
128+
}
129+
}
130+
var extraArgs = [
131+
'--dart-sdk-summary',
132+
'${toUri(sdkModule, sumId)}',
133+
'--packages',
134+
'.packages',
135+
];
136+
137+
Uri output = toUri(module, jsId);
138+
139+
List<String> args = [
140+
'--packages=${sdkRoot.toFilePath()}/.packages',
141+
_dartdevcScript,
142+
'--modules=es6',
143+
'--summarize',
144+
'--no-source-map',
145+
...sources,
146+
if (_urlMappings.isNotEmpty)
147+
'--url-mapping=${_urlMappings.entries.map((entry) => '${entry.key},${entry.value}').join(',')}',
148+
...extraArgs,
149+
for (String flag in flags) '--enable-experiment=$flag',
150+
...(transitiveDependencies
151+
.where((m) => !m.isSdk)
152+
.expand((m) => ['-s', '${toUri(m, sumId)}'])),
153+
'-o',
154+
'$output',
155+
];
156+
result = await _runProcess(
157+
Platform.resolvedExecutable, args, root.toFilePath());
158+
_checkExitCode(result, this, module);
159+
}
160+
}
161+
162+
@override
163+
void notifyCached(Module module) {
164+
if (_options.verbose) print("\ncached step: ddc on $module");
165+
}
166+
}
167+
168+
class RunD8 implements IOModularStep {
169+
@override
170+
List<DataId> get resultData => const [txtId];
171+
172+
@override
173+
bool get needsSources => false;
174+
175+
@override
176+
List<DataId> get dependencyDataNeeded => const [jsId];
177+
178+
@override
179+
List<DataId> get moduleDataNeeded => const [jsId];
180+
181+
@override
182+
bool get onlyOnMain => true;
183+
184+
@override
185+
Future<void> execute(Module module, Uri root, ModuleDataToRelativeUri toUri,
186+
List<String> flags) async {
187+
if (_options.verbose) print("\nstep: d8 on $module");
188+
189+
// Rename sdk.js to dart_sdk.js (the alternative, but more hermetic solution
190+
// would be to rename the import on all other .js files, but seems
191+
// overkill/unnecessary.
192+
if (await File.fromUri(root.resolve('dart_sdk.js')).exists()) {
193+
throw 'error: dart_sdk.js already exists.';
194+
}
195+
196+
await File.fromUri(root.resolve('sdk.js'))
197+
.copy(root.resolve('dart_sdk.js').toFilePath());
198+
var runjs = '''
199+
import { dart, _isolate_helper } from 'dart_sdk.js';
200+
import { main } from 'main.js';
201+
_isolate_helper.startRootIsolate(() => {}, []);
202+
main.main();
203+
''';
204+
205+
var wrapper =
206+
root.resolveUri(toUri(module, jsId)).toFilePath() + ".wrapper.js";
207+
await File(wrapper).writeAsString(runjs);
208+
List<String> d8Args = ['--module', wrapper];
209+
var result = await _runProcess(
210+
sdkRoot.resolve(_d8executable).toFilePath(), d8Args, root.toFilePath());
211+
212+
_checkExitCode(result, this, module);
213+
214+
await File.fromUri(root.resolveUri(toUri(module, txtId)))
215+
.writeAsString(result.stdout as String);
216+
}
217+
218+
@override
219+
void notifyCached(Module module) {
220+
if (_options.verbose) print("\ncached step: d8 on $module");
221+
}
222+
}
223+
224+
void _checkExitCode(ProcessResult result, IOModularStep step, Module module) {
225+
if (result.exitCode != 0 || _options.verbose) {
226+
stdout.write(result.stdout);
227+
stderr.write(result.stderr);
228+
}
229+
if (result.exitCode != 0) {
230+
throw "${step.runtimeType} failed on $module:\n\n"
231+
"stdout:\n${result.stdout}\n\n"
232+
"stderr:\n${result.stderr}";
233+
}
234+
}
235+
236+
Future<ProcessResult> _runProcess(
237+
String command, List<String> arguments, String workingDirectory) {
238+
if (_options.verbose) {
239+
print('command:\n$command ${arguments.join(' ')} from $workingDirectory');
240+
}
241+
return Process.run(command, arguments, workingDirectory: workingDirectory);
242+
}
243+
244+
String get _d8executable {
245+
if (Platform.isWindows) {
246+
return 'third_party/d8/windows/d8.exe';
247+
} else if (Platform.isLinux) {
248+
return 'third_party/d8/linux/d8';
249+
} else if (Platform.isMacOS) {
250+
return 'third_party/d8/macos/d8';
251+
}
252+
throw UnsupportedError('Unsupported platform.');
253+
}
254+
255+
Future<void> _createPackagesFile(
256+
Module module, Uri root, Set<Module> transitiveDependencies) async {
257+
// We create a .packages file which defines the location of this module if
258+
// it is a package. The CFE requires that if a `package:` URI of a
259+
// dependency is used in an import, then we need that package entry in the
260+
// .packages file. However, after it checks that the definition exists, the
261+
// CFE will not actually use the resolved URI if a library for the import
262+
// URI is already found in one of the provided .dill files of the
263+
// dependencies. For that reason, and to ensure that a step only has access
264+
// to the files provided in a module, we generate a .packages with invalid
265+
// folders for other packages.
266+
// TODO(sigmund): follow up with the CFE to see if we can remove the need
267+
// for the .packages entry altogether if they won't need to read the
268+
// sources.
269+
var packagesContents = StringBuffer();
270+
if (module.isPackage) {
271+
packagesContents.write('${module.name}:${module.packageBase}\n');
272+
}
273+
for (Module dependency in transitiveDependencies) {
274+
if (dependency.isPackage) {
275+
packagesContents.write('${dependency.name}:unused\n');
276+
}
277+
}
278+
279+
await File.fromUri(root.resolve('.packages'))
280+
.writeAsString('$packagesContents');
281+
}
282+
283+
String _sourceToImportUri(Module module, Uri relativeUri) {
284+
if (module.isPackage) {
285+
var basePath = module.packageBase.path;
286+
var packageRelativePath = basePath == "./"
287+
? relativeUri.path
288+
: relativeUri.path.substring(basePath.length);
289+
return 'package:${module.name}/$packageRelativePath';
290+
} else {
291+
return 'package:${_test_package}/$relativeUri';
292+
}
293+
}
294+
295+
Future<void> _resolveScripts() async {
296+
Future<String> resolve(String sdkSourcePath,
297+
[String relativeSnapshotPath]) async {
298+
String result = sdkRoot.resolve(sdkSourcePath).toFilePath();
299+
if (_options.useSdk && relativeSnapshotPath != null) {
300+
String snapshot = Uri.file(Platform.resolvedExecutable)
301+
.resolve(relativeSnapshotPath)
302+
.toFilePath();
303+
if (await File(snapshot).exists()) {
304+
return snapshot;
305+
}
306+
}
307+
return result;
308+
}
309+
310+
_dartdevcScript = await resolve(
311+
'pkg/dev_compiler/bin/dartdevc.dart', 'snapshots/dartdevc.dart.snapshot');
312+
_buildSdkScript = await resolve('pkg/dev_compiler/tool/build_sdk.dart');
313+
_patchSdkScript = await resolve('pkg/dev_compiler/tool/patch_sdk.dart');
314+
_sdkDevRuntime = await resolve('sdk/lib/_internal/js_dev_runtime');
315+
}

pkg/dev_compiler/tool/patch_sdk.dart

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,11 +34,16 @@ void main(List<String> argv) {
3434
exit(1);
3535
}
3636

37+
var sdk = 'sdk';
38+
if (argv.length > 3) {
39+
sdk = argv[3];
40+
}
41+
3742
var selfModifyTime = File(self).lastModifiedSync().millisecondsSinceEpoch;
3843

3944
var repoDir = argv[0];
4045
var patchDir = argv[1];
41-
var sdkLibIn = p.join(repoDir, 'sdk', 'lib');
46+
var sdkLibIn = p.join(repoDir, sdk, 'lib');
4247
var patchIn = p.join(patchDir, 'patch');
4348
var privateIn = p.join(patchDir, 'private');
4449
var sdkOut = p.join(argv[2], 'lib');

tools/bots/test_matrix.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -986,6 +986,18 @@
986986
"dartdevc_native"
987987
]
988988
},
989+
{
990+
"name": "ddc analyzer modular tests",
991+
"script": "out/ReleaseX64/dart-sdk/bin/dart",
992+
"testRunner": true,
993+
"arguments": [
994+
"pkg/dev_compiler/test/modular_ddc_suite.dart",
995+
"--configuration-name",
996+
"dartdevc-${system}-release",
997+
"--verbose",
998+
"--use-sdk"
999+
]
1000+
},
9891001
{
9901002
"name": "ddc kernel modular tests",
9911003
"script": "out/ReleaseX64/dart-sdk/bin/dart",

0 commit comments

Comments
 (0)