// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import 'dart:io'; import 'package:aft/aft.dart'; import 'package:aft/src/options/fail_fast_option.dart'; import 'package:aft/src/options/glob_options.dart'; import 'package:path/path.dart' as path; /// Command to bootstrap/link Dart/Flutter packages in the repo. class BootstrapCommand extends AmplifyCommand with GlobOptions, FailFastOption { BootstrapCommand() { argParser ..addFlag( 'upgrade', abbr: 'u', help: 'Runs `pub upgrade` instead of `pub get`', negatable: true, defaultsTo: true, ) ..addFlag( 'build', help: 'Runs build_runner for packages which need it', negatable: true, defaultsTo: true, ); } @override String get description => 'Links all packages in the Amplify Flutter repo ' 'to prepare for local development'; @override String get name => 'bootstrap'; @override List get aliases => ['bs']; late final bool upgrade = argResults!['upgrade'] as bool; late final bool build = argResults!['build'] as bool; /// Creates an empty `amplifyconfiguration.dart` file. Future _createEmptyConfig(PackageInfo package) async { // Only create for example apps. if (!package.isExample) { return; } final file = File( path.join(package.path, 'lib', 'amplifyconfiguration.dart'), ); if (await file.exists() || !await Directory(path.join(package.path, 'lib')).exists()) { return; } await file.create(); await file.writeAsString( ''' const amplifyconfig = \'\'\'{ "UserAgent": "aws-amplify-cli/2.0", "Version": "1.0" }\'\'\'; const amplifyEnvironments = {}; ''', ); } @override Future run() async { await super.run(); await linkPackages(); final bootstrapPackages = commandPackages.values .where( // Skip bootstrap for `aft` since it has already had `dart pub upgrade` // run with the native command, and running it again with the embedded // command could cause issues later on, esp. when the native `pub` // command is significantly newer/older than the embedded one. (pkg) => pkg.name != 'aft', ) .expand((pkg) => [pkg, pkg.example, pkg.docs]) .nonNulls; for (final package in bootstrapPackages) { await pubAction( arguments: [if (upgrade) 'upgrade' else 'get'], package: package, ); } await Future.wait([ for (final package in bootstrapPackages) _createEmptyConfig(package), ]); if (build) { final buildPackages = {}; final packageGraph = repo.getPackageGraph(includeDevDependencies: true); for (final package in bootstrapPackages) { dfs( packageGraph, root: package, (package) { // Only run build_runner for packages which need it for development, // i.e. those packages which specify worker JS files in their assets. final needsBuild = package.needsBuildRunner && (package.pubspecInfo.pubspec.flutter?.containsKey('assets') ?? false) && package.flavor == PackageFlavor.dart; if (needsBuild) { buildPackages.add(package); } }, ); } for (final package in buildPackages) { await runBuildRunner(package, logger: logger, verbose: verbose); } } logger.info('Repo successfully bootstrapped!'); } }