Skip to content

Commit d1d9aa5

Browse files
authored
[native_assets_builder] Support pub workspaces (#1911)
1 parent 962ab98 commit d1d9aa5

File tree

23 files changed

+240
-82
lines changed

23 files changed

+240
-82
lines changed

pkgs/native_assets_builder/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## 0.11.0-wip
22

3+
- **Breaking change** `runPackageName` is now required to properly support
4+
pub workspaces.
35
- Bump `package:native_assets_cli` to 0.11.0.
46

57
## 0.10.2

pkgs/native_assets_builder/lib/src/build_runner/build_planner.dart

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class NativeAssetsBuildPlanner {
2222
required this.logger,
2323
});
2424

25-
static Future<NativeAssetsBuildPlanner> fromRootPackageRoot({
26-
required Uri rootPackageRoot,
25+
static Future<NativeAssetsBuildPlanner> fromWorkingDirectory({
26+
required Uri workingDirectory,
2727
required List<Package> packagesWithNativeAssets,
2828
required Uri dartExecutable,
2929
required Logger logger,
@@ -35,7 +35,7 @@ class NativeAssetsBuildPlanner {
3535
'deps',
3636
'--json',
3737
],
38-
workingDirectory: rootPackageRoot.toFilePath(),
38+
workingDirectory: workingDirectory.toFilePath(),
3939
);
4040
final packageGraph =
4141
PackageGraph.fromPubDepsJsonString(result.stdout as String);
@@ -47,15 +47,13 @@ class NativeAssetsBuildPlanner {
4747
);
4848
}
4949

50-
List<Package>? plan({
51-
String? runPackageName,
52-
}) {
53-
final PackageGraph packageGraph;
54-
if (runPackageName != null) {
55-
packageGraph = this.packageGraph.subGraph(runPackageName);
56-
} else {
57-
packageGraph = this.packageGraph;
58-
}
50+
/// Plans in what order to run build hooks.
51+
///
52+
/// [runPackageName] provides the entry-point in the graph. The hooks of
53+
/// packages not in the transitive dependencies of [runPackageName] will not
54+
/// be run.
55+
List<Package>? plan(String runPackageName) {
56+
final packageGraph = this.packageGraph.subGraph(runPackageName);
5957
final packageMap = {
6058
for (final package in packagesWithNativeAssets) package.name: package
6159
};
@@ -136,4 +134,18 @@ class PackageGraph {
136134
]
137135
});
138136
}
137+
138+
@override
139+
String toString() {
140+
final buffer = StringBuffer();
141+
buffer.writeln('PackageGraph(');
142+
for (final node in vertices) {
143+
buffer.writeln(' $node ->');
144+
for (final neighbor in neighborsOf(node)) {
145+
buffer.writeln(' $neighbor');
146+
}
147+
}
148+
buffer.writeln(')');
149+
return buffer.toString();
150+
}
139151
}

pkgs/native_assets_builder/lib/src/build_runner/build_runner.dart

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -101,12 +101,12 @@ class NativeAssetsBuildRunner {
101101
required ApplicationAssetValidator applicationAssetValidator,
102102
required Uri workingDirectory,
103103
PackageLayout? packageLayout,
104-
String? runPackageName,
104+
required String runPackageName,
105105
required List<String> buildAssetTypes,
106106
required bool linkingEnabled,
107107
}) async {
108108
packageLayout ??=
109-
await PackageLayout.fromRootPackageRoot(_fileSystem, workingDirectory);
109+
await PackageLayout.fromWorkingDirectory(_fileSystem, workingDirectory);
110110

111111
final (buildPlan, packageGraph) = await _makePlan(
112112
hook: Hook.build,
@@ -208,12 +208,12 @@ class NativeAssetsBuildRunner {
208208
required ApplicationAssetValidator applicationAssetValidator,
209209
PackageLayout? packageLayout,
210210
Uri? resourceIdentifiers,
211-
String? runPackageName,
211+
required String runPackageName,
212212
required List<String> buildAssetTypes,
213213
required BuildResult buildResult,
214214
}) async {
215215
packageLayout ??=
216-
await PackageLayout.fromRootPackageRoot(_fileSystem, workingDirectory);
216+
await PackageLayout.fromWorkingDirectory(_fileSystem, workingDirectory);
217217

218218
final (buildPlan, packageGraph) = await _makePlan(
219219
hook: Hook.link,
@@ -775,7 +775,7 @@ ${compileResult.stdout}
775775

776776
Future<(List<Package>? plan, PackageGraph? dependencyGraph)> _makePlan({
777777
required PackageLayout packageLayout,
778-
String? runPackageName,
778+
required String runPackageName,
779779
required Hook hook,
780780
// TODO(dacoharkes): How to share these two? Make them extend each other?
781781
BuildResult? buildResult,
@@ -785,24 +785,14 @@ ${compileResult.stdout}
785785
final PackageGraph? packageGraph;
786786
switch (hook) {
787787
case Hook.build:
788-
// Build hooks are run in toplogical order.
789-
if (packagesWithHook.length <= 1 && runPackageName == null) {
790-
final dependencyGraph = PackageGraph({
791-
for (final p in packagesWithHook) p.name: [],
792-
});
793-
return (packagesWithHook, dependencyGraph);
794-
} else {
795-
final planner = await NativeAssetsBuildPlanner.fromRootPackageRoot(
796-
rootPackageRoot: packageLayout.rootPackageRoot,
797-
packagesWithNativeAssets: packagesWithHook,
798-
dartExecutable: Uri.file(Platform.resolvedExecutable),
799-
logger: logger,
800-
);
801-
final plan = planner.plan(
802-
runPackageName: runPackageName,
803-
);
804-
return (plan, planner.packageGraph);
805-
}
788+
final planner = await NativeAssetsBuildPlanner.fromWorkingDirectory(
789+
workingDirectory: packageLayout.packageConfigUri.resolve('../'),
790+
packagesWithNativeAssets: packagesWithHook,
791+
dartExecutable: Uri.file(Platform.resolvedExecutable),
792+
logger: logger,
793+
);
794+
final plan = planner.plan(runPackageName);
795+
return (plan, planner.packageGraph);
806796
case Hook.link:
807797
// Link hooks are not run in any particular order.
808798
// Link hooks are skipped if no assets for linking are provided.

pkgs/native_assets_builder/lib/src/package_layout/package_layout.dart

Lines changed: 32 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,6 @@ import 'package:package_config/package_config.dart';
1616
class PackageLayout {
1717
final FileSystem _fileSystem;
1818

19-
/// The root folder of the current dart invocation root package.
20-
///
21-
/// `$rootPackageRoot`.
22-
final Uri rootPackageRoot;
23-
2419
/// Package config containing the information of where to foot the root [Uri]s
2520
/// of other packages.
2621
///
@@ -30,8 +25,11 @@ class PackageLayout {
3025

3126
final Uri packageConfigUri;
3227

33-
PackageLayout._(this._fileSystem, this.rootPackageRoot, this.packageConfig,
34-
this.packageConfigUri);
28+
PackageLayout._(
29+
this._fileSystem,
30+
this.packageConfig,
31+
this.packageConfigUri,
32+
);
3533

3634
factory PackageLayout.fromPackageConfig(
3735
FileSystem fileSystem,
@@ -40,36 +38,53 @@ class PackageLayout {
4038
) {
4139
assert(fileSystem.file(packageConfigUri).existsSync());
4240
packageConfigUri = packageConfigUri.normalizePath();
43-
final rootPackageRoot = packageConfigUri.resolve('../');
4441
return PackageLayout._(
4542
fileSystem,
46-
rootPackageRoot,
4743
packageConfig,
4844
packageConfigUri,
4945
);
5046
}
5147

52-
static Future<PackageLayout> fromRootPackageRoot(
48+
static Future<PackageLayout> fromWorkingDirectory(
49+
FileSystem fileSystem,
50+
Uri workingDirectory,
51+
) async {
52+
workingDirectory = workingDirectory.normalizePath();
53+
final packageConfigUri =
54+
await findPackageConfig(fileSystem, workingDirectory);
55+
assert(await fileSystem.file(packageConfigUri).exists());
56+
final packageConfig = await loadPackageConfigUri(packageConfigUri!);
57+
return PackageLayout._(fileSystem, packageConfig, packageConfigUri);
58+
}
59+
60+
static Future<Uri?> findPackageConfig(
5361
FileSystem fileSystem,
5462
Uri rootPackageRoot,
5563
) async {
56-
rootPackageRoot = rootPackageRoot.normalizePath();
5764
final packageConfigUri =
5865
rootPackageRoot.resolve('.dart_tool/package_config.json');
59-
assert(await fileSystem.file(packageConfigUri).exists());
60-
final packageConfig = await loadPackageConfigUri(packageConfigUri);
61-
return PackageLayout._(
62-
fileSystem, rootPackageRoot, packageConfig, packageConfigUri);
66+
final file = fileSystem.file(packageConfigUri);
67+
if (await file.exists()) {
68+
return file.uri;
69+
}
70+
final parentUri = rootPackageRoot.resolve('../');
71+
if (parentUri == rootPackageRoot) {
72+
return null;
73+
}
74+
return findPackageConfig(fileSystem, parentUri);
6375
}
6476

6577
/// The .dart_tool directory is used to store built artifacts and caches.
6678
///
67-
/// `$rootPackageRoot/.dart_tool/`.
79+
/// This is the `.dart_tool/` directory where the package config is.
80+
///
81+
/// When pub workspaces are used, the hook results are shared across all
82+
/// packages in the workspace.
6883
///
6984
/// Each package should only modify the subfolder of `.dart_tool/` with its
7085
/// own name.
7186
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
72-
late final Uri dartTool = rootPackageRoot.resolve('.dart_tool/');
87+
late final Uri dartTool = packageConfigUri.resolve('./');
7388

7489
/// The directory where `package:native_assets_builder` stores all persistent
7590
/// information.

pkgs/native_assets_builder/test/build_runner/build_planner_test.dart

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void main() async {
3535

3636
final graph = PackageGraph.fromPubDepsJsonString(result.stdout);
3737

38-
final packageLayout = await PackageLayout.fromRootPackageRoot(
38+
final packageLayout = await PackageLayout.fromWorkingDirectory(
3939
const LocalFileSystem(), nativeAddUri);
4040
final packagesWithNativeAssets =
4141
await packageLayout.packagesWithAssets(Hook.build);
@@ -46,7 +46,7 @@ void main() async {
4646
dartExecutable: Uri.file(Platform.resolvedExecutable),
4747
logger: logger,
4848
);
49-
final buildPlan = planner.plan();
49+
final buildPlan = planner.plan('native_add');
5050
expect(buildPlan!.length, 1);
5151
expect(buildPlan.single.name, 'native_add');
5252
});
@@ -60,18 +60,18 @@ void main() async {
6060
// First, run `pub get`, we need pub to resolve our dependencies.
6161
await runPubGet(workingDirectory: nativeAddUri, logger: logger);
6262

63-
final packageLayout = await PackageLayout.fromRootPackageRoot(
63+
final packageLayout = await PackageLayout.fromWorkingDirectory(
6464
const LocalFileSystem(), nativeAddUri);
6565
final packagesWithNativeAssets =
6666
await packageLayout.packagesWithAssets(Hook.build);
6767
final nativeAssetsBuildPlanner =
68-
await NativeAssetsBuildPlanner.fromRootPackageRoot(
69-
rootPackageRoot: nativeAddUri,
68+
await NativeAssetsBuildPlanner.fromWorkingDirectory(
69+
workingDirectory: nativeAddUri,
7070
packagesWithNativeAssets: packagesWithNativeAssets,
7171
dartExecutable: Uri.file(Platform.resolvedExecutable),
7272
logger: logger,
7373
);
74-
final buildPlan = nativeAssetsBuildPlanner.plan();
74+
final buildPlan = nativeAssetsBuildPlanner.plan('native_add');
7575
expect(buildPlan!.length, 1);
7676
expect(buildPlan.single.name, 'native_add');
7777
});
@@ -87,20 +87,18 @@ void main() async {
8787
// First, run `pub get`, we need pub to resolve our dependencies.
8888
await runPubGet(workingDirectory: nativeAddUri, logger: logger);
8989

90-
final packageLayout = await PackageLayout.fromRootPackageRoot(
90+
final packageLayout = await PackageLayout.fromWorkingDirectory(
9191
const LocalFileSystem(), nativeAddUri);
9292
final packagesWithNativeAssets =
9393
await packageLayout.packagesWithAssets(Hook.build);
9494
final nativeAssetsBuildPlanner =
95-
await NativeAssetsBuildPlanner.fromRootPackageRoot(
96-
rootPackageRoot: nativeAddUri,
95+
await NativeAssetsBuildPlanner.fromWorkingDirectory(
96+
workingDirectory: nativeAddUri,
9797
packagesWithNativeAssets: packagesWithNativeAssets,
9898
dartExecutable: Uri.file(Platform.resolvedExecutable),
9999
logger: logger,
100100
);
101-
final buildPlan = nativeAssetsBuildPlanner.plan(
102-
runPackageName: runPackageName,
103-
);
101+
final buildPlan = nativeAssetsBuildPlanner.plan(runPackageName);
104102
expect(buildPlan!.length, 0);
105103
});
106104
});

pkgs/native_assets_builder/test/build_runner/build_runner_reusability_test.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ void main() async {
1515
test('multiple build invocations', timeout: longTimeout, () async {
1616
await inTempDir((tempUri) async {
1717
await copyTestProjects(targetUri: tempUri);
18-
final packageUri = tempUri.resolve('package_reading_metadata/');
18+
const packageName = 'package_reading_metadata';
19+
final packageUri = tempUri.resolve('$packageName/');
1920

2021
// First, run `pub get`, we need pub to resolve our dependencies.
2122
await runPubGet(
@@ -49,6 +50,7 @@ void main() async {
4950
inputValidator: (input) async => [],
5051
buildValidator: (input, output) async => [],
5152
applicationAssetValidator: (_) async => [],
53+
runPackageName: packageName,
5254
);
5355
await buildRunner.build(
5456
inputCreator: inputCreator,
@@ -58,6 +60,7 @@ void main() async {
5860
inputValidator: (input) async => [],
5961
buildValidator: (input, output) async => [],
6062
applicationAssetValidator: (_) async => [],
63+
runPackageName: packageName,
6164
);
6265
});
6366
});

pkgs/native_assets_builder/test/build_runner/build_runner_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ void main() async {
6565
for (final passPackageLayout in [true, false]) {
6666
PackageLayout? packageLayout;
6767
if (passPackageLayout) {
68-
packageLayout = await PackageLayout.fromRootPackageRoot(
68+
packageLayout = await PackageLayout.fromWorkingDirectory(
6969
const LocalFileSystem(), packageUri);
7070
}
7171
final logMessages = <String>[];

pkgs/native_assets_builder/test/build_runner/concurrency_shared_test_helper.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '../helpers.dart';
1111
// Is invoked concurrently multiple times in separate processes.
1212
void main(List<String> args) async {
1313
final packageUri = Uri.directory(args[0]);
14+
final packageName = packageUri.pathSegments.lastWhere((e) => e.isNotEmpty);
1415
final target = Target.fromString(args[1]);
1516

1617
final logger = Logger('')
@@ -49,6 +50,7 @@ void main(List<String> args) async {
4950
...await validateCodeAssetBuildOutput(input, output),
5051
],
5152
applicationAssetValidator: validateCodeAssetInApplication,
53+
runPackageName: packageName,
5254
);
5355
if (result == null) {
5456
throw Error();

pkgs/native_assets_builder/test/build_runner/concurrency_test_helper.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import 'helpers.dart';
1212
// Is invoked concurrently multiple times in separate processes.
1313
void main(List<String> args) async {
1414
final packageUri = Uri.directory(args[0]);
15+
final packageName = packageUri.pathSegments.lastWhere((e) => e.isNotEmpty);
1516
Duration? timeout;
1617
if (args.length >= 2) {
1718
timeout = Duration(milliseconds: int.parse(args[1]));
@@ -50,6 +51,7 @@ void main(List<String> args) async {
5051
...await validateDataAssetBuildOutput(input, output),
5152
],
5253
applicationAssetValidator: validateCodeAssetInApplication,
54+
runPackageName: packageName,
5355
);
5456
if (result == null) {
5557
throw Error();

0 commit comments

Comments
 (0)