Make Assets more robust across platforms (#14246)
diff --git a/packages/flutter_tools/lib/src/asset.dart b/packages/flutter_tools/lib/src/asset.dart index b3dc4f3..22b3481 100644 --- a/packages/flutter_tools/lib/src/asset.dart +++ b/packages/flutter_tools/lib/src/asset.dart
@@ -167,7 +167,7 @@ } for (_Asset variant in assetVariants[asset]) { assert(variant.assetFileExists); - entries[variant.assetEntry] = new DevFSFileContent(variant.assetFile); + entries[variant.entryUri.path] = new DevFSFileContent(variant.assetFile); } } @@ -177,7 +177,7 @@ } for (_Asset asset in materialAssets) { assert(asset.assetFileExists); - entries[asset.assetEntry] = new DevFSFileContent(asset.assetFile); + entries[asset.entryUri.path] = new DevFSFileContent(asset.assetFile); } entries[_kAssetManifestJson] = _createAssetManifest(assetVariants); @@ -199,38 +199,34 @@ } class _Asset { - _Asset({ this.base, String assetEntry, this.relativePath, this.source }) - : _assetEntry = assetEntry; + _Asset({ this.baseDir, this.relativeUri, this.entryUri }); - final String _assetEntry; + final String baseDir; - final String base; + /// A platform-independent Uri where this asset can be found on disk on the + /// host system relative to [baseDir]. + final Uri relativeUri; - /// The entry to list in the generated asset manifest. - String get assetEntry => _assetEntry ?? relativePath; - - /// Where the resource is on disk relative to [base]. - final String relativePath; - - final String source; + /// A platform-independent Uri representing the entry for the asset manifest. + final Uri entryUri; File get assetFile { - return fs.file(source != null ? '$base/$source' : '$base/$relativePath'); + return fs.file(fs.path.join(baseDir, fs.path.fromUri(relativeUri))); } bool get assetFileExists => assetFile.existsSync(); - /// The delta between what the assetEntry is and the relativePath (e.g., + /// The delta between what the entryUri is and the relativeUri (e.g., /// packages/flutter_gallery). - String get symbolicPrefix { - if (_assetEntry == null || _assetEntry == relativePath) + Uri get symbolicPrefixUri { + if (entryUri == relativeUri) return null; - final int index = _assetEntry.indexOf(relativePath); - return index == -1 ? null : _assetEntry.substring(0, index); + final int index = entryUri.path.indexOf(relativeUri.path); + return index == -1 ? null : new Uri(path: entryUri.path.substring(0, index)); } @override - String toString() => 'asset: $assetEntry'; + String toString() => 'asset: $entryUri'; @override bool operator ==(dynamic other) { @@ -239,18 +235,16 @@ if (other.runtimeType != runtimeType) return false; final _Asset otherAsset = other; - return otherAsset.base == base - && otherAsset.assetEntry == assetEntry - && otherAsset.relativePath == relativePath - && otherAsset.source == source; + return otherAsset.baseDir == baseDir + && otherAsset.relativeUri == relativeUri + && otherAsset.entryUri == entryUri; } @override int get hashCode { - return base.hashCode - ^assetEntry.hashCode - ^relativePath.hashCode - ^ source.hashCode; + return baseDir.hashCode + ^relativeUri.hashCode + ^ entryUri.hashCode; } } @@ -272,11 +266,11 @@ for (Map<String, dynamic> family in _getMaterialFonts(fontSet)) { for (Map<String, dynamic> font in family['fonts']) { - final String assetKey = font['asset']; + final Uri entryUri = fs.path.toUri(font['asset']); result.add(new _Asset( - base: fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'artifacts', 'material_fonts'), - source: fs.path.basename(assetKey), - relativePath: assetKey + baseDir: fs.path.join(Cache.flutterRoot, 'bin', 'cache', 'artifacts', 'material_fonts'), + relativeUri: new Uri(path: entryUri.pathSegments.last), + entryUri: entryUri )); } } @@ -361,8 +355,8 @@ for (_Asset main in assetVariants.keys) { final List<String> variants = <String>[]; for (_Asset variant in assetVariants[main]) - variants.add(variant.assetEntry); - json[main.assetEntry] = variants; + variants.add(variant.entryUri.path); + json[main.entryUri.path] = variants; } return new DevFSStringContent(JSON.encode(json)); } @@ -400,17 +394,17 @@ for (Font font in manifest.fonts) { final List<FontAsset> packageFontAssets = <FontAsset>[]; for (FontAsset fontAsset in font.fontAssets) { - final String assetPath = fontAsset.asset; - if (assetPath.startsWith('packages') && - !fs.isFileSync(packageMap.map[packageName].resolve('../$assetPath').path)) { + final Uri assetUri = fontAsset.assetUri; + if (assetUri.pathSegments.first == 'packages' && + !fs.isFileSync(fs.path.fromUri(packageMap.map[packageName].resolve('../${assetUri.path}')))) { packageFontAssets.add(new FontAsset( - fontAsset.asset, + fontAsset.assetUri, weight: fontAsset.weight, style: fontAsset.style, )); } else { packageFontAssets.add(new FontAsset( - 'packages/$packageName/${fontAsset.asset}', + new Uri(pathSegments: <String>['packages', packageName]..addAll(assetUri.pathSegments)), weight: fontAsset.weight, style: fontAsset.style, )); @@ -486,20 +480,25 @@ final Map<_Asset, List<_Asset>> result = <_Asset, List<_Asset>>{}; final _AssetDirectoryCache cache = new _AssetDirectoryCache(excludeDirs); - for (String assetName in flutterManifest.assets) { + for (Uri assetUri in flutterManifest.assets) { final _Asset asset = _resolveAsset( packageMap, assetBase, - assetName, + assetUri, packageName, ); final List<_Asset> variants = <_Asset>[]; for (String path in cache.variantsFor(asset.assetFile.path)) { - final String key = fs.path.relative(path, from: asset.base); - String assetEntry; - if (asset.symbolicPrefix != null) - assetEntry = fs.path.join(asset.symbolicPrefix, key); - variants.add(new _Asset(base: asset.base, assetEntry: assetEntry, relativePath: key)); + final String relativePath = fs.path.relative(path, from: asset.baseDir); + final Uri relativeUri = fs.path.toUri(relativePath); + final Uri entryUri = asset.symbolicPrefixUri == null + ? relativeUri + : asset.symbolicPrefixUri.resolveUri(relativeUri); + variants.add(new _Asset( + baseDir: asset.baseDir, + entryUri: entryUri, + relativeUri: relativeUri, + )); } result[asset] = variants; @@ -511,11 +510,11 @@ final _Asset baseAsset = _resolveAsset( packageMap, assetBase, - fontAsset.asset, + fontAsset.assetUri, packageName, ); if (!baseAsset.assetFileExists) { - printError('Error: unable to locate asset entry in pubspec.yaml: "${fontAsset.asset}".'); + printError('Error: unable to locate asset entry in pubspec.yaml: "${fontAsset.assetUri}".'); return null; } @@ -528,47 +527,42 @@ _Asset _resolveAsset( PackageMap packageMap, - String assetBase, - String asset, + String assetsBaseDir, + Uri assetUri, String packageName, ) { - if (asset.startsWith('packages/') && !fs.isFileSync(fs.path.join(assetBase, asset))) { + final String assetPath = fs.path.fromUri(assetUri); + if (assetUri.pathSegments.first == 'packages' && !fs.isFileSync(fs.path.join(assetsBaseDir, assetPath))) { // The asset is referenced in the pubspec.yaml as // 'packages/PACKAGE_NAME/PATH/TO/ASSET . - final _Asset packageAsset = _resolvePackageAsset(asset, packageMap); + final _Asset packageAsset = _resolvePackageAsset(assetUri, packageMap); if (packageAsset != null) return packageAsset; } - final String assetEntry = packageName != null - ? 'packages/$packageName/$asset' // Asset from, and declared in $packageName. - : null; // Asset from the current application. - return new _Asset(base: assetBase, assetEntry: assetEntry, relativePath: asset); + return new _Asset( + baseDir: assetsBaseDir, + entryUri: packageName == null + ? assetUri // Asset from the current application. + : new Uri(pathSegments: <String>['packages', packageName]..addAll(assetUri.pathSegments)), // Asset from, and declared in $packageName. + relativeUri: assetUri, + ); } -_Asset _resolvePackageAsset(String asset, PackageMap packageMap) { - assert(asset.startsWith('packages/')); - String packageKey = asset.substring('packages/'.length); - String relativeAsset = asset; - - final int index = packageKey.indexOf('/'); - if (index != -1) { - relativeAsset = packageKey.substring(index + 1); - packageKey = packageKey.substring(0, index); - - - final Uri uri = packageMap.map[packageKey]; - if (uri != null && uri.scheme == 'file') { - final File file = fs.file(uri); - final String base = file.path.substring(0, file.path.length - 1); +_Asset _resolvePackageAsset(Uri assetUri, PackageMap packageMap) { + assert(assetUri.pathSegments.first == 'packages'); + if (assetUri.pathSegments.length > 1) { + final String packageName = assetUri.pathSegments[1]; + final Uri packageUri = packageMap.map[packageName]; + if (packageUri != null && packageUri.scheme == 'file') { return new _Asset( - base: base, - assetEntry: asset, - relativePath: relativeAsset, + baseDir: fs.path.fromUri(packageUri), + entryUri: assetUri, + relativeUri: new Uri(pathSegments: assetUri.pathSegments.sublist(2)), ); } } printStatus('Error detected in pubspec.yaml:', emphasis: true); - printError('Could not resolve package $packageKey for asset $asset.\n'); + printError('Could not resolve package for asset $assetUri.\n'); return null; }
diff --git a/packages/flutter_tools/lib/src/flutter_manifest.dart b/packages/flutter_tools/lib/src/flutter_manifest.dart index e26d9f1..30e5d6b 100644 --- a/packages/flutter_tools/lib/src/flutter_manifest.dart +++ b/packages/flutter_tools/lib/src/flutter_manifest.dart
@@ -52,8 +52,8 @@ return _flutterDescriptor['fonts'] ?? const <Map<String, dynamic>>[]; } - List<String> get assets { - return _flutterDescriptor['assets'] ?? const <String>[]; + List<Uri> get assets { + return _flutterDescriptor['assets']?.map(Uri.parse)?.toList() ?? const <Uri>[]; } List<Font> _fonts; @@ -89,7 +89,7 @@ } fontAssets.add(new FontAsset( - asset, + Uri.parse(asset), weight: fontFile['weight'], style: fontFile['style'], )); @@ -122,10 +122,10 @@ } class FontAsset { - FontAsset(this.asset, {this.weight, this.style}) - : assert(asset != null); + FontAsset(this.assetUri, {this.weight, this.style}) + : assert(assetUri != null); - final String asset; + final Uri assetUri; final int weight; final String style; @@ -137,12 +137,12 @@ if (style != null) descriptor['style'] = style; - descriptor['asset'] = asset; + descriptor['asset'] = assetUri.path; return descriptor; } @override - String toString() => '$runtimeType(asset: $asset, weight; $weight, style: $style)'; + String toString() => '$runtimeType(asset: ${assetUri.path}, weight; $weight, style: $style)'; } Future<dynamic> _loadFlutterManifest(String manifestPath) async { @@ -167,4 +167,4 @@ printError(validator.errors.join('\n')); return false; } -} \ No newline at end of file +}