Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -302,21 +302,15 @@ class Tab1ItemPage extends StatefulWidget {
}

class Tab1ItemPageState extends State<Tab1ItemPage> {
@override
void initState() {
super.initState();
relatedColors = List<Color>.generate(10, (int index) {
final math.Random random = math.Random(widget.randomSeed);
return Color.fromARGB(
255,
(widget.color!.red + random.nextInt(100) - 50).clamp(0, 255),
(widget.color!.green + random.nextInt(100) - 50).clamp(0, 255),
(widget.color!.blue + random.nextInt(100) - 50).clamp(0, 255),
);
});
}

late List<Color> relatedColors;
late final List<Color> relatedColors = List<Color>.generate(10, (int index) {
final math.Random random = math.Random(widget.randomSeed);
return Color.fromARGB(
255,
(widget.color!.red + random.nextInt(100) - 50).clamp(0, 255),
(widget.color!.green + random.nextInt(100) - 50).clamp(0, 255),
(widget.color!.blue + random.nextInt(100) - 50).clamp(0, 255),
);
});

@override
Widget build(BuildContext context) {
Expand Down
3 changes: 1 addition & 2 deletions dev/integration_tests/flutter_gallery/lib/gallery/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ class GalleryApp extends StatefulWidget {
class _GalleryAppState extends State<GalleryApp> {
GalleryOptions? _options;
Timer? _timeDilationTimer;
late AppStateModel model;
late final AppStateModel model = AppStateModel()..loadProducts();

Map<String, WidgetBuilder> _buildRoutes() {
// For a different example of how to set up an application routing table
Expand All @@ -66,7 +66,6 @@ class _GalleryAppState extends State<GalleryApp> {
timeDilation: timeDilation,
platform: defaultTargetPlatform,
);
model = AppStateModel()..loadProducts();
}

@override
Expand Down
271 changes: 271 additions & 0 deletions packages/flutter_tools/lib/src/base/multi_root_file_system.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:io' as io
show
Directory,
File,
FileStat,
FileSystemEntity,
FileSystemEntityType,
Link;

import 'package:file/file.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as p; // flutter_ignore: package_path_import

/// A [FileSystem] that wraps the [delegate] file system to create an overlay of
/// files from multiple [roots].
///
/// Regular paths or `file:` URIs are resolved directly in the underlying file
/// system, but URIs that use a special [scheme] are resolved by searching
/// under a set of given roots in order.
///
/// For example, consider the following inputs:
///
/// - scheme is `multi-root`
/// - the set of roots are `/a` and `/b`
/// - the underlying file system contains files:
/// /root_a/dir/only_a.dart
/// /root_a/dir/both.dart
/// /root_b/dir/only_b.dart
/// /root_b/dir/both.dart
/// /other/other.dart
///
/// Then:
///
/// - file:///other/other.dart is resolved as /other/other.dart
/// - multi-root:///dir/only_a.dart is resolved as /root_a/dir/only_a.dart
/// - multi-root:///dir/only_b.dart is resolved as /root_b/dir/only_b.dart
/// - multi-root:///dir/both.dart is resolved as /root_a/dir/only_a.dart
class MultiRootFileSystem extends ForwardingFileSystem {
MultiRootFileSystem({
required FileSystem delegate,
required String scheme,
required List<String> roots,
}) : assert(delegate != null),
assert(roots.isNotEmpty),
_scheme = scheme,
_roots = roots.map((String root) => delegate.path.normalize(root)).toList(),
super(delegate);

@visibleForTesting
FileSystem get fileSystem => delegate;

final String _scheme;
final List<String> _roots;

@override
File file(dynamic path) => MultiRootFile(
fileSystem: this,
delegate: delegate.file(_resolve(path)),
);

@override
Directory directory(dynamic path) => MultiRootDirectory(
fileSystem: this,
delegate: delegate.directory(_resolve(path)),
);

@override
Link link(dynamic path) => MultiRootLink(
fileSystem: this,
delegate: delegate.link(_resolve(path)),
);

@override
Future<io.FileStat> stat(String path) =>
delegate.stat(_resolve(path).toString());

@override
io.FileStat statSync(String path) =>
delegate.statSync(_resolve(path).toString());

@override
Future<bool> identical(String path1, String path2) =>
delegate.identical(_resolve(path1).toString(), _resolve(path2).toString());

@override
bool identicalSync(String path1, String path2) =>
delegate.identicalSync(_resolve(path1).toString(), _resolve(path2).toString());

@override
Future<io.FileSystemEntityType> type(String path, {bool followLinks = true}) =>
delegate.type(_resolve(path).toString(), followLinks: followLinks);

@override
io.FileSystemEntityType typeSync(String path, {bool followLinks = true}) =>
delegate.typeSync(_resolve(path).toString(), followLinks: followLinks);

// Caching the path context here and clearing when the currentDirectory setter
// is updated works since the flutter tool restricts usage of dart:io directly
// via the forbidden import tests. Otherwise, the path context's current
// working directory might get out of sync, leading to unexpected results from
// methods like `path.relative`.
@override
p.Context get path => _cachedPath ??= delegate.path;
p.Context? _cachedPath;

@override
set currentDirectory(dynamic path) {
_cachedPath = null;
delegate.currentDirectory = path;
}

/// If the path is a multiroot uri, resolve to the actual path of the
/// underlying file system. Otherwise, return as is.
dynamic _resolve(dynamic path) {
Uri uri;
if (path == null) {
return null;
} else if (path is String) {
uri = Uri.parse(path);
} else if (path is Uri) {
uri = path;
} else if (path is FileSystemEntity) {
uri = path.uri;
} else {
throw ArgumentError('Invalid type for "path": ${path?.runtimeType}');
}

if (!uri.hasScheme || uri.scheme != _scheme) {
return path;
}

String? firstRootPath;
final String relativePath = delegate.path.joinAll(uri.pathSegments);
for (final String root in _roots) {
final String pathWithRoot = delegate.path.join(root, relativePath);
if (delegate.typeSync(pathWithRoot, followLinks: false) !=
FileSystemEntityType.notFound) {
return pathWithRoot;
}
firstRootPath ??= pathWithRoot;
}

// If not found, construct the path with the first root.
return firstRootPath!;
}

Uri _toMultiRootUri(Uri uri) {
if (uri.scheme != 'file') {
return uri;
}

final p.Context pathContext = delegate.path;
final bool isWindows = pathContext.style == p.Style.windows;
final String path = uri.toFilePath(windows: isWindows);
for (final String root in _roots) {
if (path.startsWith('$root${pathContext.separator}')) {
String pathWithoutRoot = path.substring(root.length + 1);
if (isWindows) {
// Convert the path from Windows style
pathWithoutRoot = p.url.joinAll(pathContext.split(pathWithoutRoot));
}
return Uri.parse('$_scheme:///$pathWithoutRoot');
}
}
return uri;
}

@override
String toString() =>
'MultiRootFileSystem(scheme = $_scheme, roots = $_roots, delegate = $delegate)';
}

abstract class MultiRootFileSystemEntity<T extends FileSystemEntity,
D extends io.FileSystemEntity> extends ForwardingFileSystemEntity<T, D> {
MultiRootFileSystemEntity({
required this.fileSystem,
required this.delegate,
});

@override
final D delegate;

@override
final MultiRootFileSystem fileSystem;

@override
File wrapFile(io.File delegate) => MultiRootFile(
fileSystem: fileSystem,
delegate: delegate,
);

@override
Directory wrapDirectory(io.Directory delegate) => MultiRootDirectory(
fileSystem: fileSystem,
delegate: delegate,
);

@override
Link wrapLink(io.Link delegate) => MultiRootLink(
fileSystem: fileSystem,
delegate: delegate,
);

@override
Uri get uri => fileSystem._toMultiRootUri(delegate.uri);
}

class MultiRootFile extends MultiRootFileSystemEntity<File, io.File>
with ForwardingFile {
MultiRootFile({
required MultiRootFileSystem fileSystem,
required io.File delegate,
}) : super(
fileSystem: fileSystem,
delegate: delegate,
);

@override
String toString() =>
'MultiRootFile(fileSystem = $fileSystem, delegate = $delegate)';
}

class MultiRootDirectory
extends MultiRootFileSystemEntity<Directory, io.Directory>
with ForwardingDirectory<Directory> {
MultiRootDirectory({
required MultiRootFileSystem fileSystem,
required io.Directory delegate,
}) : super(
fileSystem: fileSystem,
delegate: delegate,
);

// For the childEntity methods, we first obtain an instance of the entity
// from the underlying file system, then invoke childEntity() on it, then
// wrap in the ErrorHandling version.
@override
Directory childDirectory(String basename) =>
fileSystem.directory(fileSystem.path.join(delegate.path, basename));

@override
File childFile(String basename) =>
fileSystem.file(fileSystem.path.join(delegate.path, basename));

@override
Link childLink(String basename) =>
fileSystem.link(fileSystem.path.join(delegate.path, basename));

@override
String toString() =>
'MultiRootDirectory(fileSystem = $fileSystem, delegate = $delegate)';
}

class MultiRootLink extends MultiRootFileSystemEntity<Link, io.Link>
with ForwardingLink {
MultiRootLink({
required MultiRootFileSystem fileSystem,
required io.Link delegate,
}) : super(
fileSystem: fileSystem,
delegate: delegate,
);

@override
String toString() =>
'MultiRootLink(fileSystem = $fileSystem, delegate = $delegate)';
}
4 changes: 2 additions & 2 deletions packages/flutter_tools/lib/src/commands/run.dart
Original file line number Diff line number Diff line change
Expand Up @@ -608,8 +608,8 @@ class RunCommand extends RunCommandBase {
for (final Device device in devices)
await FlutterDevice.create(
device,
fileSystemRoots: stringsArg(FlutterOptions.kFileSystemRoot),
fileSystemScheme: stringArg(FlutterOptions.kFileSystemScheme),
fileSystemRoots: fileSystemRoots,
fileSystemScheme: fileSystemScheme,
experimentalFlags: expFlags,
target: targetFile,
buildInfo: buildInfo,
Expand Down
6 changes: 3 additions & 3 deletions packages/flutter_tools/lib/src/flutter_plugins.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,14 @@ void _renderTemplateToFile(String template, dynamic context, File file, Template

Plugin _pluginFromPackage(String name, Uri packageRoot, Set<String> appDependencies, {FileSystem fileSystem}) {
final FileSystem fs = fileSystem ?? globals.fs;
final String pubspecPath = fs.path.fromUri(packageRoot.resolve('pubspec.yaml'));
if (!fs.isFileSync(pubspecPath)) {
final File pubspecFile = fs.file(packageRoot.resolve('pubspec.yaml'));
if (!pubspecFile.existsSync()) {
return null;
}
dynamic pubspec;

try {
pubspec = loadYaml(fs.file(pubspecPath).readAsStringSync());
pubspec = loadYaml(pubspecFile.readAsStringSync());
} on YamlException catch (err) {
globals.printTrace('Failed to parse plugin manifest for $name: $err');
// Do nothing, potentially not a plugin.
Expand Down
Loading