| // Copyright 2020 The Dart Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| // Note: this is a copy from flutter tools, updated to work with dwds tests |
| |
| import 'package:dwds/asset_reader.dart'; |
| import 'package:dwds/config.dart'; |
| import 'package:file/file.dart'; |
| import 'package:path/path.dart' as p; |
| import 'package:test_common/test_sdk_layout.dart'; |
| |
| import 'asset_server.dart'; |
| import 'bootstrap.dart'; |
| import 'frontend_server_client.dart'; |
| |
| class WebDevFS { |
| WebDevFS({ |
| required this.fileSystem, |
| required this.hostname, |
| required this.port, |
| required this.projectDirectory, |
| required this.packageUriMapper, |
| required this.index, |
| required this.soundNullSafety, |
| this.urlTunneler, |
| required this.sdkLayout, |
| }); |
| |
| final FileSystem fileSystem; |
| late final TestAssetServer assetServer; |
| final String hostname; |
| final int port; |
| final Uri projectDirectory; |
| final PackageUriMapper packageUriMapper; |
| final String index; |
| final UrlEncoder? urlTunneler; |
| final bool soundNullSafety; |
| final TestSdkLayout sdkLayout; |
| late final Directory _savedCurrentDirectory; |
| |
| Future<Uri> create() async { |
| _savedCurrentDirectory = fileSystem.currentDirectory; |
| |
| fileSystem.currentDirectory = projectDirectory.toFilePath(); |
| |
| assetServer = await TestAssetServer.start(sdkLayout.sdkDirectory, |
| fileSystem, index, hostname, port, urlTunneler, packageUriMapper); |
| return Uri.parse('http://$hostname:$port'); |
| } |
| |
| Future<void> dispose() { |
| fileSystem.currentDirectory = _savedCurrentDirectory; |
| return assetServer.close(); |
| } |
| |
| Future<UpdateFSReport> update({ |
| required Uri mainUri, |
| required String dillOutputPath, |
| required ResidentCompiler generator, |
| required List<Uri> invalidatedFiles, |
| }) async { |
| final mainPath = mainUri.toFilePath(); |
| final outputDirectoryPath = fileSystem.file(mainPath).parent.path; |
| final entryPoint = mainUri.toString(); |
| |
| var require = 'require.js'; |
| var stackMapper = 'stack_trace_mapper.js'; |
| var main = 'main.dart.js'; |
| var bootstrap = 'main_module.bootstrap.js'; |
| |
| // If base path is not overwritten, use main's subdirectory |
| // to store all files, so the paths match the requests. |
| if (assetServer.basePath.isEmpty) { |
| final directory = p.dirname(entryPoint); |
| require = '$directory/require.js'; |
| stackMapper = '$directory/stack_trace_mapper.js'; |
| main = '$directory/main.dart.js'; |
| bootstrap = '$directory/main_module.bootstrap.js'; |
| } |
| |
| assetServer.writeFile( |
| entryPoint, fileSystem.file(mainPath).readAsStringSync()); |
| assetServer.writeFile(require, requireJS.readAsStringSync()); |
| assetServer.writeFile(stackMapper, stackTraceMapper.readAsStringSync()); |
| assetServer.writeFile( |
| main, |
| generateBootstrapScript( |
| requireUrl: 'require.js', |
| mapperUrl: 'stack_trace_mapper.js', |
| entrypoint: entryPoint, |
| ), |
| ); |
| assetServer.writeFile( |
| bootstrap, |
| generateMainModule( |
| entrypoint: entryPoint, |
| ), |
| ); |
| |
| assetServer.writeFile('main_module.digests', '{}'); |
| |
| var sdk = soundNullSafety ? dartSdk : dartSdkWeak; |
| var sdkSourceMap = |
| soundNullSafety ? dartSdkSourcemap : dartSdkSourcemapWeak; |
| assetServer.writeFile('dart_sdk.js', sdk.readAsStringSync()); |
| assetServer.writeFile('dart_sdk.js.map', sdkSourceMap.readAsStringSync()); |
| |
| generator.reset(); |
| var compilerOutput = await generator.recompile( |
| Uri.parse('org-dartlang-app:///$mainUri'), |
| invalidatedFiles, |
| outputPath: p.join(dillOutputPath, 'app.dill'), |
| packageConfig: packageUriMapper.packageConfig, |
| ); |
| if (compilerOutput == null || compilerOutput.errorCount > 0) { |
| return UpdateFSReport(success: false); |
| } |
| |
| File codeFile; |
| File manifestFile; |
| File sourcemapFile; |
| File metadataFile; |
| List<String> modules; |
| try { |
| var parentDirectory = fileSystem.directory(outputDirectoryPath); |
| codeFile = |
| parentDirectory.childFile('${compilerOutput.outputFilename}.sources'); |
| manifestFile = |
| parentDirectory.childFile('${compilerOutput.outputFilename}.json'); |
| sourcemapFile = |
| parentDirectory.childFile('${compilerOutput.outputFilename}.map'); |
| metadataFile = parentDirectory |
| .childFile('${compilerOutput.outputFilename}.metadata'); |
| modules = assetServer.write( |
| codeFile, manifestFile, sourcemapFile, metadataFile); |
| } on FileSystemException catch (err) { |
| throw Exception('Failed to load recompiled sources:\n$err'); |
| } |
| return UpdateFSReport( |
| success: true, |
| syncedBytes: codeFile.lengthSync(), |
| invalidatedSourcesCount: invalidatedFiles.length, |
| )..invalidatedModules = modules; |
| } |
| |
| File get requireJS => fileSystem.file(sdkLayout.requireJsPath); |
| File get dartSdkWeak => fileSystem.file(sdkLayout.weakJsPath); |
| File get dartSdk => fileSystem.file(sdkLayout.soundJsPath); |
| File get dartSdkSourcemapWeak => fileSystem.file(sdkLayout.weakJsMapPath); |
| File get dartSdkSourcemap => fileSystem.file(sdkLayout.soundJsMapPath); |
| File get stackTraceMapper => fileSystem.file(sdkLayout.stackTraceMapperPath); |
| } |
| |
| class UpdateFSReport { |
| final bool _success; |
| final int _invalidatedSourcesCount; |
| final int _syncedBytes; |
| |
| UpdateFSReport({ |
| bool success = false, |
| int invalidatedSourcesCount = 0, |
| int syncedBytes = 0, |
| }) : _success = success, |
| _invalidatedSourcesCount = invalidatedSourcesCount, |
| _syncedBytes = syncedBytes; |
| |
| bool get success => _success; |
| int get invalidatedSourcesCount => _invalidatedSourcesCount; |
| int get syncedBytes => _syncedBytes; |
| |
| /// JavaScript modules produced by the incremental compiler in `dartdevc` |
| /// mode. |
| /// |
| /// Only used for JavaScript compilation. |
| List<String>? invalidatedModules; |
| } |