blob: 00b97d2ec19e105c653d437725f5d58d9f636f81 [file] [log] [blame]
// Copyright (c) 2023, 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:package_config/package_config.dart';
/// Directory layout for dealing with native assets.
///
/// Build scripts for native assets will be run from the context of another
/// root package.
///
/// The directory layout follows pub's convention for caching:
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
class PackageLayout {
/// The root folder of the current dart invocation root package.
///
/// `$rootPackageRoot`.
final Uri rootPackageRoot;
/// Package config containing the information of where to foot the root [Uri]s
/// of other packages.
///
/// Can be `null` to enable quick construction of a
/// [PackageLayout].
final PackageConfig packageConfig;
final Uri packageConfigUri;
PackageLayout._(
this.rootPackageRoot, this.packageConfig, this.packageConfigUri);
factory PackageLayout.fromPackageConfig(
PackageConfig packageConfig,
Uri packageConfigUri,
) {
assert(File.fromUri(packageConfigUri).existsSync());
packageConfigUri = packageConfigUri.normalizePath();
final rootPackageRoot = packageConfigUri.resolve('../');
return PackageLayout._(rootPackageRoot, packageConfig, packageConfigUri);
}
static Future<PackageLayout> fromRootPackageRoot(Uri rootPackageRoot) async {
rootPackageRoot = rootPackageRoot.normalizePath();
final packageConfigUri =
rootPackageRoot.resolve('.dart_tool/package_config.json');
assert(await File.fromUri(packageConfigUri).exists());
final packageConfig = await loadPackageConfigUri(packageConfigUri);
return PackageLayout._(rootPackageRoot, packageConfig, packageConfigUri);
}
/// The .dart_tool directory is used to store built artifacts and caches.
///
/// `$rootPackageRoot/.dart_tool/`.
///
/// Each package should only modify the subfolder of `.dart_tool/` with its
/// own name.
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
late final Uri dartTool = rootPackageRoot.resolve('.dart_tool/');
/// The directory where `package:native_assets_builder` stores all persistent
/// information.
///
/// This folder is owned by `package:native_assets_builder`, no other package
/// should read or modify it.
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
///
/// `$rootPackageRoot/.dart_tool/native_assets_builder/`.
late final Uri dartToolNativeAssetsBuilder =
dartTool.resolve('native_assets_builder/');
/// The root of `package:$packageName`.
///
/// `$packageName/`.
///
/// This folder is owned by pub, and should _never_ be written to.
Uri packageRoot(String packageName) {
final package = packageConfig[packageName];
if (package == null) {
throw StateError('Package $packageName not found in packageConfig.');
}
return package.root;
}
/// All packages in [packageConfig] with native assets.
///
/// Whether a package has native assets is defined by whether it contains
/// a `build.dart`.
///
/// `package:native` itself is excluded.
late final Future<List<Package>> packagesWithNativeAssets = () async {
final result = <Package>[];
for (final package in packageConfig.packages) {
final packageRoot = package.root;
if (packageRoot.scheme == 'file') {
if (await File.fromUri(packageRoot.resolve('build.dart')).exists()) {
result.add(package);
}
}
}
return result;
}();
}