Unverified Commit 27876e09 authored by Jonah Williams's avatar Jonah Williams Committed by GitHub

Revert "Devfs cleanup and testing (#33374)" (#33673)

This reverts commit 445505d6.
parent b7bd5768
......@@ -36,9 +36,10 @@ Future<void> main(List<String> args) {
});
}
void writeFile(libfs.File outputFile, DevFSContent content) {
Future<void> writeFile(libfs.File outputFile, DevFSContent content) async {
outputFile.createSync(recursive: true);
content.copyToFile(outputFile);
final List<int> data = await content.contentsAsBytes();
outputFile.writeAsBytesSync(data);
}
Future<void> run(List<String> args) async {
......@@ -70,10 +71,12 @@ Future<void> run(List<String> args) async {
exit(1);
}
final List<Future<void>> calls = <Future<void>>[];
assets.entries.forEach((String fileName, DevFSContent content) {
final libfs.File outputFile = libfs.fs.file(libfs.fs.path.join(assetDir, fileName));
writeFile(outputFile, content);
calls.add(writeFile(outputFile, content));
});
await Future.wait<void>(calls);
final String outputMan = argResults[_kOptionAssetManifestOut];
await writeFuchsiaManifest(assets, argResults[_kOptionAsset], outputMan, argResults[_kOptionComponentName]);
......
......@@ -147,7 +147,7 @@ Future<void> build({
if (assets == null)
throwToolExit('Error building assets', exitCode: 1);
assemble(
await assemble(
buildMode: buildMode,
assetBundle: assets,
kernelContent: kernelContent,
......@@ -182,14 +182,14 @@ Future<AssetBundle> buildAssets({
return assetBundle;
}
void assemble({
Future<void> assemble({
BuildMode buildMode,
AssetBundle assetBundle,
DevFSContent kernelContent,
String privateKeyPath = defaultPrivateKeyPath,
String assetDirPath,
String compilationTraceFilePath,
}) {
}) async {
assetDirPath ??= getAssetBuildDirectory();
printTrace('Building bundle');
......@@ -214,21 +214,22 @@ void assemble({
printTrace('Writing asset files to $assetDirPath');
ensureDirectoryExists(assetDirPath);
writeBundle(fs.directory(assetDirPath), assetEntries);
await writeBundle(fs.directory(assetDirPath), assetEntries);
printTrace('Wrote $assetDirPath');
}
void writeBundle(
Future<void> writeBundle(
Directory bundleDir,
Map<String, DevFSContent> assetEntries,
) {
) async {
if (bundleDir.existsSync())
bundleDir.deleteSync(recursive: true);
bundleDir.createSync(recursive: true);
for (MapEntry<String, DevFSContent> entry in assetEntries.entries) {
final File file = fs.file(fs.path.join(bundleDir.path, entry.key));
file.parent.createSync(recursive: true);
entry.value.copyToFile(file);
}
await Future.wait<void>(
assetEntries.entries.map<Future<void>>((MapEntry<String, DevFSContent> entry) async {
final File file = fs.file(fs.path.join(bundleDir.path, entry.key));
file.parent.createSync(recursive: true);
await file.writeAsBytes(await entry.value.contentsAsBytes());
}));
}
......@@ -242,7 +242,7 @@ class TestCommand extends FastFlutterCommand {
throwToolExit('Error: Failed to build asset bundle');
}
if (_needRebuild(assetBundle.entries)) {
writeBundle(fs.directory(fs.path.join('build', 'unit_test_assets')),
await writeBundle(fs.directory(fs.path.join('build', 'unit_test_assets')),
assetBundle.entries);
}
}
......
......@@ -38,25 +38,21 @@ abstract class DevFSContent {
/// or if the given time is null.
bool isModifiedAfter(DateTime time);
/// The number of bytes in this file.
int get size;
/// Returns the raw bytes of this file.
List<int> contentsAsBytes();
Future<List<int>> contentsAsBytes();
/// Returns a gzipped representation of the contents of this file.
List<int> contentsAsCompressedBytes() {
return gzip.encode(contentsAsBytes());
Stream<List<int>> contentsAsStream();
Stream<List<int>> contentsAsCompressedStream() {
return contentsAsStream().cast<List<int>>().transform<List<int>>(gzip.encoder);
}
/// Copies the content into the provided file.
///
/// Requires that the `destination` directory already exists, but the target
/// file need not.
void copyToFile(File destination);
/// Return the list of files this content depends on.
List<String> get fileDependencies => <String>[];
}
/// File content to be copied to the device.
// File content to be copied to the device.
class DevFSFileContent extends DevFSContent {
DevFSFileContent(this.file);
......@@ -106,6 +102,9 @@ class DevFSFileContent extends DevFSContent {
}
}
@override
List<String> get fileDependencies => <String>[_getFile().path];
@override
bool get isModified {
final FileStat _oldFileStat = _fileStat;
......@@ -136,12 +135,10 @@ class DevFSFileContent extends DevFSContent {
}
@override
List<int> contentsAsBytes() => _getFile().readAsBytesSync().cast<int>();
Future<List<int>> contentsAsBytes() => _getFile().readAsBytes();
@override
void copyToFile(File destination) {
_getFile().copySync(destination.path);
}
Stream<List<int>> contentsAsStream() => _getFile().openRead();
}
/// Byte content to be copied to the device.
......@@ -178,15 +175,14 @@ class DevFSByteContent extends DevFSContent {
int get size => _bytes.length;
@override
List<int> contentsAsBytes() => _bytes;
Future<List<int>> contentsAsBytes() async => _bytes;
@override
void copyToFile(File destination) {
destination.writeAsBytesSync(contentsAsBytes());
}
Stream<List<int>> contentsAsStream() =>
Stream<List<int>>.fromIterable(<List<int>>[_bytes]);
}
/// String content to be copied to the device encoded as utf8.
/// String content to be copied to the device.
class DevFSStringContent extends DevFSByteContent {
DevFSStringContent(String string)
: _string = string,
......@@ -207,30 +203,76 @@ class DevFSStringContent extends DevFSByteContent {
}
}
class DevFSOperations {
DevFSOperations(this.vmService, this.fsName)
: httpAddress = vmService.httpAddress;
final VMService vmService;
final String fsName;
final Uri httpAddress;
final HttpClient _client = HttpClient();
/// Abstract DevFS operations interface.
abstract class DevFSOperations {
Future<Uri> create(String fsName);
Future<dynamic> destroy(String fsName);
Future<dynamic> writeFile(String fsName, Uri deviceUri, DevFSContent content);
}
static const int kMaxInFlight = 6;
/// An implementation of [DevFSOperations] that speaks to the
/// vm service.
class ServiceProtocolDevFSOperations implements DevFSOperations {
ServiceProtocolDevFSOperations(this.vmService);
int _inFlight = 0;
Map<Uri, DevFSContent> _outstanding;
Completer<void> _completer;
final VMService vmService;
@override
Future<Uri> create(String fsName) async {
final Map<String, dynamic> response = await vmService.vm.createDevFS(fsName);
return Uri.parse(response['uri']);
}
Future<void> destroy(String fsName) async {
@override
Future<dynamic> destroy(String fsName) async {
await vmService.vm.deleteDevFS(fsName);
}
@override
Future<dynamic> writeFile(String fsName, Uri deviceUri, DevFSContent content) async {
List<int> bytes;
try {
bytes = await content.contentsAsBytes();
} catch (e) {
return e;
}
final String fileContents = base64.encode(bytes);
try {
return await vmService.vm.invokeRpcRaw(
'_writeDevFSFile',
params: <String, dynamic>{
'fsName': fsName,
'uri': deviceUri.toString(),
'fileContents': fileContents,
},
);
} catch (error) {
printTrace('DevFS: Failed to write $deviceUri: $error');
}
}
}
class DevFSException implements Exception {
DevFSException(this.message, [this.error, this.stackTrace]);
final String message;
final dynamic error;
final StackTrace stackTrace;
}
class _DevFSHttpWriter {
_DevFSHttpWriter(this.fsName, VMService serviceProtocol)
: httpAddress = serviceProtocol.httpAddress;
final String fsName;
final Uri httpAddress;
static const int kMaxInFlight = 6;
int _inFlight = 0;
Map<Uri, DevFSContent> _outstanding;
Completer<void> _completer;
final HttpClient _client = HttpClient();
Future<void> write(Map<Uri, DevFSContent> entries) async {
_client.maxConnectionsPerHost = kMaxInFlight;
_completer = Completer<void>();
......@@ -259,9 +301,9 @@ class DevFSOperations {
final HttpClientRequest request = await _client.putUrl(httpAddress);
request.headers.removeAll(HttpHeaders.acceptEncodingHeader);
request.headers.add('dev_fs_name', fsName);
request.headers.add('dev_fs_uri_b64',
base64.encode(utf8.encode(deviceUri.toString())));
request.add(content.contentsAsCompressedBytes());
request.headers.add('dev_fs_uri_b64', base64.encode(utf8.encode('$deviceUri')));
final Stream<List<int>> contents = content.contentsAsCompressedStream();
await request.addStream(contents);
final HttpClientResponse response = await request.close();
await response.drain<void>();
} catch (error, trace) {
......@@ -275,14 +317,6 @@ class DevFSOperations {
}
}
class DevFSException implements Exception {
DevFSException(this.message, [this.error, this.stackTrace]);
final String message;
final dynamic error;
final StackTrace stackTrace;
}
// Basic statistics for DevFS update operation.
class UpdateFSReport {
UpdateFSReport({
......@@ -319,7 +353,8 @@ class DevFS {
this.fsName,
this.rootDirectory, {
String packagesFilePath,
}) : _operations = DevFSOperations(serviceProtocol, fsName),
}) : _operations = ServiceProtocolDevFSOperations(serviceProtocol),
_httpWriter = _DevFSHttpWriter(fsName, serviceProtocol),
_packagesFilePath = packagesFilePath ?? fs.path.join(rootDirectory.path, kPackagesFileName);
DevFS.operations(
......@@ -327,9 +362,11 @@ class DevFS {
this.fsName,
this.rootDirectory, {
String packagesFilePath,
}) : _packagesFilePath = packagesFilePath ?? fs.path.join(rootDirectory.path, kPackagesFileName);
}) : _httpWriter = null,
_packagesFilePath = packagesFilePath ?? fs.path.join(rootDirectory.path, kPackagesFileName);
final DevFSOperations _operations;
final _DevFSHttpWriter _httpWriter;
final String fsName;
final Directory rootDirectory;
String _packagesFilePath;
......@@ -452,7 +489,7 @@ class DevFS {
printTrace('Updating files');
if (dirtyEntries.isNotEmpty) {
try {
await _operations.write(dirtyEntries);
await _httpWriter.write(dirtyEntries);
} on SocketException catch (socketException, stackTrace) {
printTrace('DevFS sync failed. Lost connection to device: $socketException');
throw DevFSException('Lost connection to device.', socketException, stackTrace);
......
......@@ -52,7 +52,7 @@ Future<void> _buildAssets(
final Map<String, DevFSContent> assetEntries =
Map<String, DevFSContent>.from(assets.entries);
writeBundle(fs.directory(assetDir), assetEntries);
await writeBundle(fs.directory(assetDir), assetEntries);
final String appName = fuchsiaProject.project.manifest.appName;
final String outDir = getFuchsiaBuildDirectory();
......
......@@ -120,7 +120,8 @@ class ResidentWebRunner extends ResidentRunner {
if (build != 0) {
throwToolExit('Error: Failed to build asset bundle');
}
writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries);
await writeBundle(
fs.directory(getAssetBuildDirectory()), assetBundle.entries);
// Step 2: Start an HTTP server
_server = WebAssetServer(flutterProject, target, ipv6);
......
......@@ -119,7 +119,7 @@ class WebDevice extends Device {
if (build != 0) {
throwToolExit('Error: Failed to build asset bundle');
}
writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries);
await writeBundle(fs.directory(getAssetBuildDirectory()), assetBundle.entries);
_package = package;
_server = await HttpServer.bind(InternetAddress.loopbackIPv4, 0);
......
......@@ -74,7 +74,7 @@ $fontsSection
final String entryKey = 'packages/$packageName/$packageFont';
expect(bundle.entries.containsKey(entryKey), true);
expect(
utf8.decode(bundle.entries[entryKey].contentsAsBytes()),
utf8.decode(await bundle.entries[entryKey].contentsAsBytes()),
packageFont,
);
}
......@@ -82,14 +82,14 @@ $fontsSection
for (String localFont in localFonts) {
expect(bundle.entries.containsKey(localFont), true);
expect(
utf8.decode(bundle.entries[localFont].contentsAsBytes()),
utf8.decode(await bundle.entries[localFont].contentsAsBytes()),
localFont,
);
}
}
expect(
json.decode(utf8.decode(bundle.entries['FontManifest.json'].contentsAsBytes())),
json.decode(utf8.decode(await bundle.entries['FontManifest.json'].contentsAsBytes())),
json.decode(expectedAssetManifest),
);
}
......
......@@ -79,14 +79,14 @@ $assetsSection
final String entryKey = Uri.encodeFull('packages/$packageName/$asset');
expect(bundle.entries.containsKey(entryKey), true, reason: 'Cannot find key on bundle: $entryKey');
expect(
utf8.decode(bundle.entries[entryKey].contentsAsBytes()),
utf8.decode(await bundle.entries[entryKey].contentsAsBytes()),
asset,
);
}
}
expect(
utf8.decode(bundle.entries['AssetManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest,
);
}
......@@ -126,11 +126,11 @@ $assetsSection
expect(bundle.entries.length, 3); // LICENSE, AssetManifest, FontManifest
const String expectedAssetManifest = '{}';
expect(
utf8.decode(bundle.entries['AssetManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest,
);
expect(
utf8.decode(bundle.entries['FontManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['FontManifest.json'].contentsAsBytes()),
'[]',
);
}, overrides: <Type, Generator>{
......@@ -153,11 +153,11 @@ $assetsSection
expect(bundle.entries.length, 3); // LICENSE, AssetManifest, FontManifest
const String expectedAssetManifest = '{}';
expect(
utf8.decode(bundle.entries['AssetManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest,
);
expect(
utf8.decode(bundle.entries['FontManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['FontManifest.json'].contentsAsBytes()),
'[]',
);
}, overrides: <Type, Generator>{
......
......@@ -50,7 +50,7 @@ void main() {
expect(bundle.entries.length, 1);
const String expectedAssetManifest = '{}';
expect(
utf8.decode(bundle.entries['AssetManifest.json'].contentsAsBytes()),
utf8.decode(await bundle.entries['AssetManifest.json'].contentsAsBytes()),
expectedAssetManifest,
);
}, overrides: <Type, Generator>{
......
......@@ -76,7 +76,7 @@ flutter:
// The main asset file, /a/b/c/foo, and its variants exist.
for (String asset in assets) {
expect(bundle.entries.containsKey(asset), true);
expect(utf8.decode(bundle.entries[asset].contentsAsBytes()), asset);
expect(utf8.decode(await bundle.entries[asset].contentsAsBytes()), asset);
}
fs.file(fixPath('a/b/c/foo')).deleteSync();
......@@ -88,7 +88,7 @@ flutter:
expect(bundle.entries.containsKey('a/b/c/foo'), false);
for (String asset in assets.skip(1)) {
expect(bundle.entries.containsKey(asset), true);
expect(utf8.decode(bundle.entries[asset].contentsAsBytes()), asset);
expect(utf8.decode(await bundle.entries[asset].contentsAsBytes()), asset);
}
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
......
......@@ -7,7 +7,6 @@ import 'dart:async';
import 'package:flutter_tools/src/asset.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/cache.dart';
import 'package:flutter_tools/src/convert.dart';
import 'src/common.dart';
import 'src/context.dart';
......@@ -66,5 +65,5 @@ void main() {
}
Future<String> getValueAsString(String key, AssetBundle asset) async {
return utf8.decode(asset.entries[key].contentsAsBytes());
return String.fromCharCodes(await asset.entries[key].contentsAsBytes());
}
This diff is collapsed.
......@@ -14,6 +14,7 @@ import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/base/platform.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/compile.dart';
import 'package:flutter_tools/src/devfs.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/ios/devices.dart';
import 'package:flutter_tools/src/ios/simulators.dart';
......@@ -477,6 +478,30 @@ class BasicMock {
}
}
class MockDevFSOperations extends BasicMock implements DevFSOperations {
Map<Uri, DevFSContent> devicePathToContent = <Uri, DevFSContent>{};
@override
Future<Uri> create(String fsName) async {
messages.add('create $fsName');
return Uri.parse('file:///$fsName');
}
@override
Future<dynamic> destroy(String fsName) async {
messages.add('destroy $fsName');
}
@override
Future<dynamic> writeFile(String fsName, Uri deviceUri, DevFSContent content) async {
String message = 'writeFile $fsName $deviceUri';
if (content is DevFSFileContent) {
message += ' ${content.file.path}';
}
messages.add(message);
devicePathToContent[deviceUri] = content;
}
}
class MockResidentCompiler extends BasicMock implements ResidentCompiler {
@override
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment