blob: 8cd68efacc8e40088514822ef19232dd5bf804a4 [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 'package:file/file.dart';
import 'package:package_config/package_config.dart';
import '../build_runner/build_runner.dart';
/// Directory layout for dealing with native assets.
///
/// For the [NativeAssetsBuildRunner] to correctly run hooks, multiple pieces of
/// information are required:
/// * [packageConfig] to know the list of all packages that may contain hooks.
/// * [packageConfigUri] to be able to get a dependency graph with `pub` and to
/// know where to cache/share asset builds.
/// * [runPackageName] to know which package build hooks to invoke and ignore.
/// Only dependencies of the "run package" are built.
///
/// The [NativeAssetsBuildRunner] builds assets in
/// `.dart_tool/hooks_runner/`. The directory layout follows pub's
/// convention for caching:
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
class PackageLayout {
/// Package config containing the information of where to find the root [Uri]s
/// of other packages.
///
/// Can be `null` to enable quick construction of a
/// [PackageLayout].
final PackageConfig packageConfig;
final Uri packageConfigUri;
/// Only assets of transitive dependencies of [runPackageName] are built.
final String runPackageName;
/// Include the dev dependencies of [runPackageName].
final bool includeDevDependencies;
PackageLayout._(
this.packageConfig,
this.packageConfigUri,
this.runPackageName, {
required this.includeDevDependencies,
});
factory PackageLayout.fromPackageConfig(
FileSystem fileSystem,
PackageConfig packageConfig,
Uri packageConfigUri,
String runPackageName, {
required bool includeDevDependencies,
}) {
assert(fileSystem.file(packageConfigUri).existsSync());
packageConfigUri = packageConfigUri.normalizePath();
return PackageLayout._(
packageConfig,
packageConfigUri,
runPackageName,
includeDevDependencies: includeDevDependencies,
);
}
static Future<PackageLayout> fromWorkingDirectory(
FileSystem fileSystem,
Uri workingDirectory,
String runPackageName, {
required bool includeDevDependencies,
}) async {
workingDirectory = workingDirectory.normalizePath();
final packageConfigUri = await findPackageConfig(
fileSystem,
workingDirectory,
);
assert(await fileSystem.file(packageConfigUri).exists());
final packageConfig = await loadPackageConfigUri(packageConfigUri!);
return PackageLayout._(
packageConfig,
packageConfigUri,
runPackageName,
includeDevDependencies: includeDevDependencies,
);
}
static Future<Uri?> findPackageConfig(
FileSystem fileSystem,
Uri rootPackageRoot,
) async {
final packageConfigUri = rootPackageRoot.resolve(
'.dart_tool/package_config.json',
);
final file = fileSystem.file(packageConfigUri);
if (await file.exists()) {
return file.uri;
}
final parentUri = rootPackageRoot.resolve('../');
if (parentUri == rootPackageRoot) {
return null;
}
return findPackageConfig(fileSystem, parentUri);
}
/// The .dart_tool directory is used to store built artifacts and caches.
///
/// This is the `.dart_tool/` directory where the package config is.
///
/// When pub workspaces are used, the hook results are shared across all
/// packages in the workspace.
///
/// 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 = packageConfigUri.resolve('./');
/// The directory where `package:hooks_runner` stores all persistent
/// information.
///
/// This folder is owned by `package:hooks_runnner`, no other package
/// should read or modify it.
/// https://dart.dev/tools/pub/package-layout#project-specific-caching-for-tools
///
/// `$rootPackageRoot/.dart_tool/hooks_runner/`.
late final Uri dartToolHooksRunner = dartTool.resolve('hooks_runner/');
/// 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;
}
}