Skip to content

Commit

Permalink
[native_assets_cli] Redesign API step 1 (#946)
Browse files Browse the repository at this point in the history
  • Loading branch information
dcharkes authored Mar 14, 2024
1 parent f4e5ebc commit 4fc6a33
Show file tree
Hide file tree
Showing 112 changed files with 3,488 additions and 2,228 deletions.
4 changes: 4 additions & 0 deletions pkgs/native_assets_builder/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.6.0-wip

- **Breaking change** Completely rewritten API in `native_assets_cli`.

## 0.5.0

- **Breaking change**: Hide implementation of `KernelAssets`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,11 @@ class PackageGraph {

PackageGraph(this.map);

/// Construct a graph from the JSON produced by `dart pub deps --json`.
/// Constructs a graph from the JSON produced by `dart pub deps --json`.
factory PackageGraph.fromPubDepsJsonString(String json) =>
PackageGraph.fromPubDepsJson(jsonDecode(json) as Map<dynamic, dynamic>);

/// Construct a graph from the JSON produced by `dart pub deps --json`.
/// Constructs a graph from the JSON produced by `dart pub deps --json`.
factory PackageGraph.fromPubDepsJson(Map<dynamic, dynamic> map) {
final result = <String, List<String>>{};
final packages = map['packages'] as List<dynamic>;
Expand Down
120 changes: 74 additions & 46 deletions pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,17 @@ class NativeAssetsBuildRunner {
/// If provided, only native assets of all transitive dependencies of
/// [runPackageName] are built.
Future<BuildResult> build({
required LinkModePreference linkModePreference,
required LinkModePreferenceImpl linkModePreference,
required Target target,
required Uri workingDirectory,
required BuildMode buildMode,
CCompilerConfig? cCompilerConfig,
IOSSdk? targetIOSSdk,
required BuildModeImpl buildMode,
CCompilerConfigImpl? cCompilerConfig,
IOSSdkImpl? targetIOSSdk,
int? targetAndroidNdkApi,
required bool includeParentEnvironment,
PackageLayout? packageLayout,
String? runPackageName,
Iterable<String>? supportedAssetTypes,
}) async {
packageLayout ??= await PackageLayout.fromRootPackageRoot(workingDirectory);
final packagesWithNativeAssets =
Expand Down Expand Up @@ -77,7 +78,7 @@ class NativeAssetsBuildRunner {
buildPlan = plan;
packageGraph = planner.packageGraph;
}
final assets = <Asset>[];
final assets = <AssetImpl>[];
final dependencies = <Uri>[];
final metadata = <String, Metadata>{};
var success = true;
Expand All @@ -98,6 +99,7 @@ class NativeAssetsBuildRunner {
cCompilerConfig: cCompilerConfig,
targetIOSSdk: targetIOSSdk,
targetAndroidNdkApi: targetAndroidNdkApi,
supportedAssetTypes: supportedAssetTypes,
);
final (
packageAssets,
Expand Down Expand Up @@ -132,12 +134,13 @@ class NativeAssetsBuildRunner {
/// If provided, only native assets of all transitive dependencies of
/// [runPackageName] are built.
Future<DryRunResult> dryRun({
required LinkModePreference linkModePreference,
required OS targetOs,
required LinkModePreferenceImpl linkModePreference,
required OSImpl targetOS,
required Uri workingDirectory,
required bool includeParentEnvironment,
PackageLayout? packageLayout,
String? runPackageName,
Iterable<String>? supportedAssetTypes,
}) async {
packageLayout ??= await PackageLayout.fromRootPackageRoot(workingDirectory);
final packagesWithNativeAssets =
Expand All @@ -163,15 +166,16 @@ class NativeAssetsBuildRunner {
}
buildPlan = plan;
}
final assets = <Asset>[];
final assets = <AssetImpl>[];
var success = true;
for (final package in buildPlan) {
final config = await _cliConfigDryRun(
packageName: package.name,
packageRoot: packageLayout.packageRoot(package.name),
targetOs: targetOs,
targetOS: targetOS,
linkMode: linkModePreference,
buildParentDir: packageLayout.dartToolNativeAssetsBuilder,
supportedAssetTypes: supportedAssetTypes,
);
final (packageAssets, _, _, packageSuccess) = await _buildPackage(
config,
Expand All @@ -180,7 +184,26 @@ class NativeAssetsBuildRunner {
includeParentEnvironment,
dryRun: true,
);
assets.addAll(packageAssets);
for (final asset in packageAssets) {
switch (asset) {
case NativeCodeAssetImpl _:
if (asset.architecture != null) {
// Backwards compatibility, if an architecture is provided use it.
assets.add(asset);
} else {
// Dry run does not report architecture. Dart VM branches on OS
// and Target when looking up assets, so populate assets for all
// architectures.
for (final architecture in asset.os.architectures) {
assets.add(asset.copyWith(
architecture: architecture,
));
}
}
case DataAssetImpl _:
assets.add(asset);
}
}
success &= packageSuccess;
}
return _DryRunResultImpl(
Expand All @@ -190,21 +213,21 @@ class NativeAssetsBuildRunner {
}

Future<_PackageBuildRecord> _buildPackageCached(
BuildConfig config,
BuildConfigImpl config,
Uri packageConfigUri,
Uri workingDirectory,
bool includeParentEnvironment,
) async {
final packageName = config.packageName;
final outDir = config.outDir;
final outDir = config.outputDirectory;
if (!await Directory.fromUri(outDir).exists()) {
await Directory.fromUri(outDir).create(recursive: true);
}

final buildOutput = await BuildOutput.readFromFile(outDir: outDir);
final buildOutput = await BuildOutputImpl.readFromFile(outDir: outDir);
final lastBuilt = buildOutput?.timestamp.roundDownToSeconds() ??
DateTime.fromMillisecondsSinceEpoch(0);
final dependencies = buildOutput?.dependencies;
final dependencies = buildOutput?.dependenciesModel;
final lastChange = await dependencies?.lastModified() ?? DateTime.now();

if (lastBuilt.isAfter(lastChange)) {
Expand All @@ -213,8 +236,8 @@ class NativeAssetsBuildRunner {
// All build flags go into [outDir]. Therefore we do not have to check
// here whether the config is equal.
final assets = buildOutput!.assets;
final dependencies = buildOutput.dependencies.dependencies;
final metadata = buildOutput.metadata;
final dependencies = buildOutput.dependencies;
final metadata = buildOutput.metadataModel;
return (assets, dependencies, metadata, true);
}

Expand All @@ -228,19 +251,20 @@ class NativeAssetsBuildRunner {
}

Future<_PackageBuildRecord> _buildPackage(
BuildConfig config,
BuildConfigImpl config,
Uri packageConfigUri,
Uri workingDirectory,
bool includeParentEnvironment, {
required bool dryRun,
}) async {
final outDir = config.outDir;
final outDir = config.outputDirectory;
final configFile = outDir.resolve('../config.yaml');
final buildDotDart = config.packageRoot.resolve('build.dart');
final configFileContents = config.toYamlString();
logger.info('config.yaml contents: $configFileContents');
await File.fromUri(configFile).writeAsString(configFileContents);
final buildOutputFile = File.fromUri(outDir.resolve(BuildOutput.fileName));
final buildOutputFile =
File.fromUri(outDir.resolve(BuildOutputImpl.fileName));
if (await buildOutputFile.exists()) {
// Ensure we'll never read outdated build results.
await buildOutputFile.delete();
Expand Down Expand Up @@ -282,11 +306,11 @@ ${result.stdout}
}

try {
final buildOutput = await BuildOutput.readFromFile(outDir: outDir);
final buildOutput = await BuildOutputImpl.readFromFile(outDir: outDir);
final assets = buildOutput?.assets ?? [];
success &= validateAssetsPackage(assets, config.packageName);
final dependencies = buildOutput?.dependencies.dependencies ?? [];
final metadata = dryRun ? null : buildOutput?.metadata;
final dependencies = buildOutput?.dependencies ?? [];
final metadata = dryRun ? null : buildOutput?.metadataModel;
return (assets, dependencies, metadata, success);
} on FormatException catch (e) {
logger.severe('''
Expand All @@ -295,7 +319,7 @@ build_output.yaml contained a format error.
${e.message}
''');
success = false;
return (<Asset>[], <Uri>[], const Metadata({}), false);
return (<NativeCodeAssetImpl>[], <Uri>[], const Metadata({}), false);
// TODO(https://github.com/dart-lang/native/issues/109): Stop throwing
// type errors in native_assets_cli, release a new version of that package
// and then remove this.
Expand All @@ -306,53 +330,55 @@ Building native assets for package:${config.packageName} failed.
build_output.yaml contained a format error.
''');
success = false;
return (<Asset>[], <Uri>[], const Metadata({}), false);
return (<NativeCodeAssetImpl>[], <Uri>[], const Metadata({}), false);
} finally {
if (!success) {
final buildOutputFile =
File.fromUri(outDir.resolve(BuildOutput.fileName));
File.fromUri(outDir.resolve(BuildOutputImpl.fileName));
if (await buildOutputFile.exists()) {
await buildOutputFile.delete();
}
}
}
}

static Future<BuildConfig> _cliConfig({
static Future<BuildConfigImpl> _cliConfig({
required String packageName,
required Uri packageRoot,
required Target target,
IOSSdk? targetIOSSdk,
IOSSdkImpl? targetIOSSdk,
int? targetAndroidNdkApi,
required BuildMode buildMode,
required LinkModePreference linkMode,
required BuildModeImpl buildMode,
required LinkModePreferenceImpl linkMode,
required Uri buildParentDir,
CCompilerConfig? cCompilerConfig,
CCompilerConfigImpl? cCompilerConfig,
DependencyMetadata? dependencyMetadata,
Iterable<String>? supportedAssetTypes,
}) async {
final buildDirName = BuildConfig.checksum(
final buildDirName = BuildConfigImpl.checksum(
packageName: packageName,
packageRoot: packageRoot,
targetOs: target.os,
targetOS: target.os,
targetArchitecture: target.architecture,
buildMode: buildMode,
linkModePreference: linkMode,
targetIOSSdk: targetIOSSdk,
cCompiler: cCompilerConfig,
dependencyMetadata: dependencyMetadata,
targetAndroidNdkApi: targetAndroidNdkApi,
supportedAssetTypes: supportedAssetTypes,
);
final outDirUri = buildParentDir.resolve('$buildDirName/out/');
final outDir = Directory.fromUri(outDirUri);
if (!await outDir.exists()) {
// TODO(https://dartbug.com/50565): Purge old or unused folders.
await outDir.create(recursive: true);
}
return BuildConfig(
return BuildConfigImpl(
outDir: outDirUri,
packageName: packageName,
packageRoot: packageRoot,
targetOs: target.os,
targetOS: target.os,
targetArchitecture: target.architecture,
buildMode: buildMode,
linkModePreference: linkMode,
Expand All @@ -363,25 +389,27 @@ build_output.yaml contained a format error.
);
}

static Future<BuildConfig> _cliConfigDryRun({
static Future<BuildConfigImpl> _cliConfigDryRun({
required String packageName,
required Uri packageRoot,
required OS targetOs,
required LinkModePreference linkMode,
required OSImpl targetOS,
required LinkModePreferenceImpl linkMode,
required Uri buildParentDir,
Iterable<String>? supportedAssetTypes,
}) async {
final buildDirName = 'dry_run_${targetOs}_$linkMode';
final buildDirName = 'dry_run_${targetOS}_$linkMode';
final outDirUri = buildParentDir.resolve('$buildDirName/out/');
final outDir = Directory.fromUri(outDirUri);
if (!await outDir.exists()) {
await outDir.create(recursive: true);
}
return BuildConfig.dryRun(
return BuildConfigImpl.dryRun(
outDir: outDirUri,
packageName: packageName,
packageRoot: packageRoot,
targetOs: targetOs,
targetOS: targetOS,
linkModePreference: linkMode,
supportedAssetTypes: supportedAssetTypes,
);
}

Expand All @@ -400,7 +428,7 @@ build_output.yaml contained a format error.
};
}

bool validateAssetsPackage(List<Asset> assets, String packageName) {
bool validateAssetsPackage(Iterable<AssetImpl> assets, String packageName) {
final invalidAssetIds = assets
.map((a) => a.id)
.where((n) => !n.startsWith('package:$packageName/'))
Expand All @@ -419,16 +447,16 @@ build_output.yaml contained a format error.
}

typedef _PackageBuildRecord = (
List<Asset>,
List<Uri> dependencies,
Iterable<AssetImpl>,
Iterable<Uri> dependencies,
Metadata?,
bool success,
);

/// The result from a [NativeAssetsBuildRunner.dryRun].
abstract interface class DryRunResult {
/// The native assets for all [Target]s for the build or dry run.
List<Asset> get assets;
List<AssetImpl> get assets;

/// Whether all builds completed without errors.
///
Expand All @@ -438,7 +466,7 @@ abstract interface class DryRunResult {

final class _DryRunResultImpl implements DryRunResult {
@override
final List<Asset> assets;
final List<AssetImpl> assets;

@override
final bool success;
Expand All @@ -462,7 +490,7 @@ abstract class BuildResult implements DryRunResult {

final class _BuildResultImpl implements BuildResult {
@override
final List<Asset> assets;
final List<AssetImpl> assets;

@override
final List<Uri> dependencies;
Expand Down
12 changes: 7 additions & 5 deletions pkgs/native_assets_builder/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
name: native_assets_builder
description: >-
This package is the backend that invokes top-level `build.dart` scripts.
version: 0.5.0
version: 0.6.0-wip
repository: https://github.com/dart-lang/native/tree/main/pkgs/native_assets_builder

environment:
sdk: '>=3.0.0 <4.0.0'
sdk: '>=3.3.0 <4.0.0'

publish_to: none

dependencies:
graphs: ^2.3.1
logging: ^1.2.0
native_assets_cli: ^0.4.2
# native_assets_cli:
# path: ../native_assets_cli/
# native_assets_cli: ^0.4.2
native_assets_cli:
path: ../native_assets_cli/
package_config: ^2.1.0
yaml: ^3.1.2
yaml_edit: ^2.1.0
Expand Down
Loading

0 comments on commit 4fc6a33

Please sign in to comment.