| // Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file |
| // for details. 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'; |
| |
| import 'package:code_assets/code_assets.dart'; |
| import 'package:dartdev/src/native_assets_macos.dart'; |
| import 'package:data_assets/data_assets.dart'; |
| import 'package:hooks/hooks.dart'; |
| import 'package:hooks_runner/hooks_runner.dart'; |
| |
| final libOutputDirectoryUriFromBin = |
| Uri.file('../').resolveUri(libOutputDirectoryUri); |
| final libOutputDirectoryUri = Uri.file('lib/'); |
| final dataOutputDirectoryUri = Uri.file('assets/'); |
| |
| Future<KernelAssets> bundleNativeAssets( |
| Iterable<EncodedAsset> assets, |
| Target target, |
| Uri outputUri, { |
| required bool relocatable, |
| bool verbose = false, |
| }) async { |
| final targetMapping = _targetMapping(assets, target, outputUri, relocatable); |
| await _copyAssets(targetMapping, target, outputUri, relocatable, verbose); |
| return KernelAssets(targetMapping.map((asset) => asset.target).toList()); |
| } |
| |
| Future<Uri> writeNativeAssetsYaml( |
| KernelAssets assets, |
| Uri outputUri, { |
| String? header, |
| }) async { |
| final nativeAssetsYamlUri = outputUri.resolve('native_assets.yaml'); |
| final nativeAssetsYamlFile = File(nativeAssetsYamlUri.toFilePath()); |
| await nativeAssetsYamlFile.create(recursive: true); |
| |
| var contents = assets.toNativeAssetsFile(); |
| if (header != null) { |
| contents = '$header\n$contents'; |
| } |
| |
| await nativeAssetsYamlFile.writeAsString(contents); |
| return nativeAssetsYamlUri; |
| } |
| |
| Future<void> _copyAssets( |
| List<({Object asset, KernelAsset target})> targetMapping, |
| Target target, |
| Uri outputUri, |
| bool relocatable, |
| bool verbose, |
| ) async { |
| final filesToCopy = <({String id, Uri src, Uri dest})>[]; |
| final codeAssetUris = <Uri>[]; |
| |
| for (final (:asset, :target) in targetMapping) { |
| final targetPath = target.path; |
| if (targetPath |
| case KernelAssetRelativePath(:final uri) || |
| KernelAssetAbsolutePath(:final uri)) { |
| final targetUri = outputUri.resolveUri(uri); |
| |
| switch (asset) { |
| case CodeAsset(:final file!): |
| filesToCopy.add(( |
| id: asset.id, |
| src: file, |
| dest: targetUri, |
| )); |
| codeAssetUris.add(targetUri); |
| case DataAsset(:final file): |
| filesToCopy.add(( |
| id: asset.id, |
| src: file, |
| dest: targetUri, |
| )); |
| default: |
| throw UnimplementedError(); |
| } |
| } |
| } |
| |
| if (filesToCopy.isNotEmpty) { |
| if (verbose) { |
| stdout.writeln( |
| 'Copying ${filesToCopy.length} build assets:\n' |
| '${filesToCopy.map((e) => e.id).join('\n')}', |
| ); |
| } |
| |
| // TODO(https://dartbug.com/59668): Cache copying and rewriting of install names |
| await Future.wait(filesToCopy.map((file) => file.src.copyTo(file.dest))); |
| |
| if (target.os == OS.macOS) { |
| await rewriteInstallNames(codeAssetUris, relocatable: relocatable); |
| } |
| } |
| } |
| |
| List<({Object asset, KernelAsset target})> _targetMapping( |
| Iterable<EncodedAsset> assets, |
| Target target, |
| Uri outputUri, |
| bool relocatable, |
| ) { |
| final codeAssets = |
| assets.where((asset) => asset.isCodeAsset).map(CodeAsset.fromEncoded); |
| final dataAssets = |
| assets.where((asset) => asset.isDataAsset).map(DataAsset.fromEncoded); |
| |
| return [ |
| for (final asset in codeAssets) |
| ( |
| asset: asset, |
| target: asset.targetLocation(target, outputUri, relocatable) |
| ), |
| for (final asset in dataAssets) |
| ( |
| asset: asset, |
| target: asset.targetLocation(target, outputUri, relocatable) |
| ), |
| ]; |
| } |
| |
| extension on CodeAsset { |
| KernelAsset targetLocation(Target target, Uri outputUri, bool relocatable) { |
| final kernelAssetPath = switch (linkMode) { |
| DynamicLoadingSystem(:final uri) => KernelAssetSystemPath(uri), |
| LookupInExecutable() => KernelAssetInExecutable(), |
| LookupInProcess() => KernelAssetInProcess(), |
| DynamicLoadingBundled() => () { |
| final relativeUri = |
| libOutputDirectoryUriFromBin.resolve(file!.pathSegments.last); |
| return relocatable |
| ? KernelAssetRelativePath(relativeUri) |
| : KernelAssetAbsolutePath(outputUri.resolveUri(relativeUri)); |
| }(), |
| _ => throw UnsupportedError( |
| 'Unsupported NativeCodeAsset linkMode ${linkMode.runtimeType} in asset $this', |
| ), |
| }; |
| return KernelAsset( |
| id: id, |
| target: target, |
| path: kernelAssetPath, |
| ); |
| } |
| } |
| |
| extension on DataAsset { |
| KernelAsset targetLocation(Target target, Uri outputUri, bool relocatable) { |
| final relativeUri = dataOutputDirectoryUri.resolve(file.pathSegments.last); |
| return KernelAsset( |
| id: id, |
| target: target, |
| path: relocatable |
| ? KernelAssetRelativePath(relativeUri) |
| : KernelAssetAbsolutePath(outputUri.resolveUri(relativeUri)), |
| ); |
| } |
| } |
| |
| extension on Uri { |
| Future<void> copyTo(Uri targetUri) async { |
| await File.fromUri(targetUri).create(recursive: true); |
| await File.fromUri(this).copy(targetUri.toFilePath()); |
| } |
| } |