From 091793029db964310140fc8601ac559d7a5021c7 Mon Sep 17 00:00:00 2001 From: Joel Winarske Date: Mon, 15 Jun 2026 20:29:22 -0700 Subject: [PATCH] style: format with the Dart 3.12 formatter Apply `dart format` (tall style) across bin/, lib/, and test/. No logic changes. Signed-off-by: Joel Winarske --- bin/emb.dart | 6 +- lib/src/aot/aot_builder.dart | 171 +++++++++++------- lib/src/bundle/bundle_builder.dart | 18 +- lib/src/command_runner.dart | 16 +- lib/src/commands/aot_command.dart | 28 +-- lib/src/commands/build_command.dart | 45 +++-- lib/src/commands/bundle_command.dart | 15 +- lib/src/commands/deps_command.dart | 76 +++++--- lib/src/commands/doctor_command.dart | 12 +- lib/src/commands/engine_command.dart | 35 ++-- lib/src/commands/env_command.dart | 7 +- lib/src/commands/flutter_command.dart | 32 ++-- lib/src/commands/setup_command.dart | 136 +++++++++----- lib/src/commands/sync_command.dart | 25 +-- lib/src/commands/update_command.dart | 8 +- lib/src/engine/engine_artifacts.dart | 21 ++- lib/src/flutter/flutter_sdk.dart | 24 +-- lib/src/host/host_info.dart | 24 +-- lib/src/manifest/emb_manifest.dart | 16 +- lib/src/manifest/host_deps.dart | 36 ++-- lib/src/manifest/manifest_loader.dart | 35 ++-- lib/src/pkg/_platform/brew_provisioner.dart | 3 +- lib/src/pkg/_platform/winget_provisioner.dart | 8 +- lib/src/pkg/packagekit_provisioner.dart | 25 ++- lib/src/pkg/provision_models.dart | 6 +- lib/src/repo/git_repo.dart | 56 +++--- lib/src/repo/repo_syncer.dart | 4 +- lib/src/workspace/workspace.dart | 8 +- test/src/aot/aot_builder_test.dart | 61 +++++-- test/src/bundle/bundle_builder_test.dart | 64 +++++-- test/src/command_runner_test.dart | 43 ++--- test/src/commands/setup_command_test.dart | 31 ++-- test/src/commands/update_command_test.dart | 168 ++++++++--------- test/src/deps/dependency_resolver_test.dart | 97 +++++----- test/src/flutter/flutter_sdk_test.dart | 21 ++- test/src/host/host_info_test.dart | 14 +- test/src/manifest/host_deps_test.dart | 44 ++--- test/src/manifest/manifest_loader_test.dart | 20 +- test/src/repo/git_repo_test.dart | 21 ++- 39 files changed, 853 insertions(+), 627 deletions(-) diff --git a/bin/emb.dart b/bin/emb.dart index 2bf49d2..6f093f7 100644 --- a/bin/emb.dart +++ b/bin/emb.dart @@ -16,6 +16,8 @@ Future main(List args) async { /// exited already. This is useful to prevent Future chains from proceeding /// after you've decided to exit. Future _flushThenExit(int status) { - return Future.wait([stdout.close(), stderr.close()]) - .then((_) => exit(status)); + return Future.wait([ + stdout.close(), + stderr.close(), + ]).then((_) => exit(status)); } diff --git a/lib/src/aot/aot_builder.dart b/lib/src/aot/aot_builder.dart index 0d2c1f5..195a8ee 100644 --- a/lib/src/aot/aot_builder.dart +++ b/lib/src/aot/aot_builder.dart @@ -62,7 +62,8 @@ class AotBuilder { List args, { required String workingDirectory, Map? environment, - }) runProcess; + }) + runProcess; static Future _defaultRun( String executable, @@ -81,10 +82,26 @@ class AotBuilder { } String get _flutterBin => FlutterSdk(workspace).flutterBin; - Directory get _hostEngine => Directory(p.join(workspace.flutterDir.path, - 'bin', 'cache', 'artifacts', 'engine', 'linux-x64')); - Directory get _engineCommon => Directory(p.join(workspace.flutterDir.path, - 'bin', 'cache', 'artifacts', 'engine', 'common')); + Directory get _hostEngine => Directory( + p.join( + workspace.flutterDir.path, + 'bin', + 'cache', + 'artifacts', + 'engine', + 'linux-x64', + ), + ); + Directory get _engineCommon => Directory( + p.join( + workspace.flutterDir.path, + 'bin', + 'cache', + 'artifacts', + 'engine', + 'common', + ), + ); String get _dartSdkBin => p.join(workspace.flutterDir.path, 'bin', 'cache', 'dart-sdk', 'bin'); @@ -102,11 +119,11 @@ class AotBuilder { 'profile' => '--profile', _ => '--release', }; - final code = await runProcess( - _flutterBin, - ['build', 'bundle', flag], - workingDirectory: p.absolute(appPath), - ); + final code = await runProcess(_flutterBin, [ + 'build', + 'bundle', + flag, + ], workingDirectory: p.absolute(appPath)); return code == 0; } @@ -132,32 +149,39 @@ class AotBuilder { ]); } - final newScheme = File(p.join(_hostEngine.path, - 'frontend_server_aot.dart.snapshot')) - .existsSync(); + final newScheme = File( + p.join(_hostEngine.path, 'frontend_server_aot.dart.snapshot'), + ).existsSync(); final targetArch = arch ?? host.machineArch; final gen = genSnapshot ?? await _resolveGenSnapshot(targetArch, modes); final results = []; for (final mode in modes) { onStep?.call('[$mode] flutter build bundle'); - if (await runProcess(_flutterBin, ['build', 'bundle'], - workingDirectory: app) != + if (await runProcess(_flutterBin, [ + 'build', + 'bundle', + ], workingDirectory: app) != 0) { - results.add(AotModeResult( - mode: mode, - success: false, - message: 'flutter build bundle failed', - )); + results.add( + AotModeResult( + mode: mode, + success: false, + message: 'flutter build bundle failed', + ), + ); continue; } final buildDir = _firstBuildDir(app); if (buildDir == null) { - results.add(AotModeResult( + results.add( + AotModeResult( mode: mode, success: false, - message: 'No .dart_tool/flutter_build/ dir found')); + message: 'No .dart_tool/flutter_build/ dir found', + ), + ); continue; } @@ -170,44 +194,51 @@ class AotBuilder { newScheme: newScheme, ); if (kernelOk != 0) { - results.add(AotModeResult( - mode: mode, success: false, message: 'kernel snapshot failed')); + results.add( + AotModeResult( + mode: mode, + success: false, + message: 'kernel snapshot failed', + ), + ); continue; } onStep?.call('[$mode] gen_snapshot app-aot-elf'); if (gen == null) { final token = EngineArtifacts.engineArch(targetArch); - results.add(AotModeResult( + results.add( + AotModeResult( mode: mode, success: false, - message: 'No $token gen_snapshot for engine ' + message: + 'No $token gen_snapshot for engine ' '${workspace.engineCommit() ?? ""} — run ' '`emb engine --arch $targetArch` (its gen_snapshot must come ' - 'from the same engine as the SDK frontend_server)')); + 'from the same engine as the SDK frontend_server)', + ), + ); continue; } final out = 'libapp.so.$mode'; final (genExe, genLead) = _genSnapshotInvocation(gen); - final genCode = await runProcess( - genExe, - [ - ...genLead, - '--deterministic', - '--snapshot_kind=app-aot-elf', - '--elf=$out', - '--strip', - '--obfuscate', - p.join(buildDir, 'app.dill'), - ], - workingDirectory: app, + final genCode = await runProcess(genExe, [ + ...genLead, + '--deterministic', + '--snapshot_kind=app-aot-elf', + '--elf=$out', + '--strip', + '--obfuscate', + p.join(buildDir, 'app.dill'), + ], workingDirectory: app); + results.add( + AotModeResult( + mode: mode, + success: genCode == 0, + output: genCode == 0 ? p.join(app, out) : null, + message: genCode == 0 ? null : 'gen_snapshot failed', + ), ); - results.add(AotModeResult( - mode: mode, - success: genCode == 0, - output: genCode == 0 ? p.join(app, out) : null, - message: genCode == 0 ? null : 'gen_snapshot failed', - )); } return AotResult(results); } @@ -228,12 +259,16 @@ class AotBuilder { ? 'frontend_server_aot.dart.snapshot' : 'frontend_server.dart.snapshot', ); - final depfile = p.join(buildDir, - newScheme ? 'kernel_snapshot_program.d' : 'kernel_snapshot.d'); + final depfile = p.join( + buildDir, + newScheme ? 'kernel_snapshot_program.d' : 'kernel_snapshot.d', + ); final isRelease = mode == 'release'; - var patched = p.join(_engineCommon.path, - isRelease ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk'); + var patched = p.join( + _engineCommon.path, + isRelease ? 'flutter_patched_sdk_product' : 'flutter_patched_sdk', + ); if (!Directory(patched).existsSync()) { patched = p.join(_engineCommon.path, 'flutter_patched_sdk'); } @@ -241,7 +276,8 @@ class AotBuilder { final args = [ '--disable-dart-dev', frontend, - '--sdk-root', '$patched/', + '--sdk-root', + '$patched/', '--target=flutter', '--no-print-incremental-dependencies', '-Ddart.vm.profile=${mode == "profile"}', @@ -251,10 +287,14 @@ class AotBuilder { if (mode == 'profile') '--track-widget-creation', '--aot', '--tfa', - '--target-os', 'linux', - '--packages', p.join(app, '.dart_tool', 'package_config.json'), - '--output-dill', p.join(buildDir, 'app.dill'), - '--depfile', depfile, + '--target-os', + 'linux', + '--packages', + p.join(app, '.dart_tool', 'package_config.json'), + '--output-dill', + p.join(buildDir, 'app.dill'), + '--depfile', + depfile, ..._sourceFlags(app), ..._nativeAssets(buildDir), '--verbosity=error', @@ -265,12 +305,15 @@ class AotBuilder { /// Optional dart_plugin_registrant source flags (mirrors create_aot.py). List _sourceFlags(String app) { - final reg = File(p.join( - app, '.dart_tool', 'flutter_build', 'dart_plugin_registrant.dart')); + final reg = File( + p.join(app, '.dart_tool', 'flutter_build', 'dart_plugin_registrant.dart'), + ); if (!reg.existsSync()) return const []; return [ - '--source', 'file://${reg.path}', - '--source', 'package:flutter/src/dart_plugin_registrant.dart', + '--source', + 'file://${reg.path}', + '--source', + 'package:flutter/src/dart_plugin_registrant.dart', '-Dflutter.dart_plugin_registrant=file://${reg.path}', ]; } @@ -301,11 +344,13 @@ class AotBuilder { final commit = workspace.engineCommit(); if (commit != null) { for (final mode in [...modes, 'release', 'profile', 'debug']) { - final dir = Directory(p.join( - workspace.platformDir('flutter-engine').path, - commit, - 'engine-sdk-$mode-$targetToken', - )); + final dir = Directory( + p.join( + workspace.platformDir('flutter-engine').path, + commit, + 'engine-sdk-$mode-$targetToken', + ), + ); if (!dir.existsSync()) continue; for (final e in dir.listSync(recursive: true, followLinks: false)) { if (e is! File || p.basename(e.path) != 'gen_snapshot') continue; diff --git a/lib/src/bundle/bundle_builder.dart b/lib/src/bundle/bundle_builder.dart index a6e9a11..2f57774 100644 --- a/lib/src/bundle/bundle_builder.dart +++ b/lib/src/bundle/bundle_builder.dart @@ -43,10 +43,12 @@ class BundleBuilder { final Workspace workspace; /// The engine bundle directory staged by `emb engine` for [mode]/[arch]. - Directory engineBundleDir(String mode, String arch) => Directory(p.join( - workspace.platformDir('flutter-engine').path, - 'bundle-$mode-${EngineArtifacts.engineArch(arch)}', - )); + Directory engineBundleDir(String mode, String arch) => Directory( + p.join( + workspace.platformDir('flutter-engine').path, + 'bundle-$mode-${EngineArtifacts.engineArch(arch)}', + ), + ); /// Assemble the bundle for the app at [appPath] into [outputDir]. BundleResult assemble({ @@ -63,16 +65,16 @@ class BundleBuilder { final libapp = File(p.join(app, 'libapp.so.$mode')); final engineDir = engineBundleDir(mode, arch); final icu = File(p.join(engineDir.path, 'data', 'icudtl.dat')); - final engineSo = - File(p.join(engineDir.path, 'lib', 'libflutter_engine.so')); + final engineSo = File( + p.join(engineDir.path, 'lib', 'libflutter_engine.so'), + ); final missing = [ if (!assets.existsSync()) 'flutter_assets — run `emb bundle --build` (or flutter build bundle)', if (!isDebug && !libapp.existsSync()) 'libapp.so.$mode — run `emb aot --mode $mode`', - if (!icu.existsSync()) - 'icudtl.dat — run `emb engine --arch $arch`', + if (!icu.existsSync()) 'icudtl.dat — run `emb engine --arch $arch`', if (!engineSo.existsSync()) 'libflutter_engine.so — run `emb engine --arch $arch`', ]; diff --git a/lib/src/command_runner.dart b/lib/src/command_runner.dart index 7ee4118..4131007 100644 --- a/lib/src/command_runner.dart +++ b/lib/src/command_runner.dart @@ -19,12 +19,10 @@ const description = 'Flutter Embedder CLI Tool'; /// {@endtemplate} class EmbCliCommandRunner extends CompletionCommandRunner { /// {@macro emb_cli_command_runner} - EmbCliCommandRunner({ - Logger? logger, - PubUpdater? pubUpdater, - }) : _logger = logger ?? Logger(), - _pubUpdater = pubUpdater ?? PubUpdater(), - super(executableName, description) { + EmbCliCommandRunner({Logger? logger, PubUpdater? pubUpdater}) + : _logger = logger ?? Logger(), + _pubUpdater = pubUpdater ?? PubUpdater(), + super(executableName, description) { // Add root options and flags argParser ..addFlag( @@ -142,11 +140,9 @@ class EmbCliCommandRunner extends CompletionCommandRunner { if (!isUpToDate) { _logger ..info('') - ..info( - ''' + ..info(''' ${lightYellow.wrap('Update available!')} ${lightCyan.wrap(packageVersion)} \u2192 ${lightCyan.wrap(latestVersion)} -Run ${lightCyan.wrap('$executableName update')} to update''', - ); +Run ${lightCyan.wrap('$executableName update')} to update'''); } } catch (_) {} } diff --git a/lib/src/commands/aot_command.dart b/lib/src/commands/aot_command.dart index 66cb191..92a4095 100644 --- a/lib/src/commands/aot_command.dart +++ b/lib/src/commands/aot_command.dart @@ -16,12 +16,13 @@ class AotCommand extends Command { required Logger logger, HostInfo? host, AotBuilder Function(Workspace ws, HostInfo host, String? glibcSysroot)? - builderFactory, - }) : _logger = logger, - _host = host, - _builderFactory = builderFactory ?? - ((ws, host, sysroot) => - AotBuilder(ws, host: host, glibcSysroot: sysroot)) { + builderFactory, + }) : _logger = logger, + _host = host, + _builderFactory = + builderFactory ?? + ((ws, host, sysroot) => + AotBuilder(ws, host: host, glibcSysroot: sysroot)) { argParser ..addOption( 'app-path', @@ -43,7 +44,8 @@ class AotCommand extends Command { ) ..addOption( 'arch', - help: 'Target arch for the engine gen_snapshot (defaults to host). ' + help: + 'Target arch for the engine gen_snapshot (defaults to host). ' 'Use e.g. arm64 to cross-build for a Raspberry Pi.', ) ..addOption( @@ -52,7 +54,8 @@ class AotCommand extends Command { ) ..addOption( 'glibc-sysroot', - help: 'Directory with ld-linux + libc to run gen_snapshot under ' + help: + 'Directory with ld-linux + libc to run gen_snapshot under ' "(defaults to the artifact's bundled clang_x64/lib64).", ); } @@ -60,7 +63,7 @@ class AotCommand extends Command { final Logger _logger; final HostInfo? _host; final AotBuilder Function(Workspace ws, HostInfo host, String? glibcSysroot) - _builderFactory; + _builderFactory; @override String get description => @@ -82,8 +85,11 @@ class AotCommand extends Command { return ExitCode.usage.code; } - final builder = - _builderFactory(workspace, host, args['glibc-sysroot'] as String?); + final builder = _builderFactory( + workspace, + host, + args['glibc-sysroot'] as String?, + ); final result = await builder.build( appPath: appPath, modes: args['mode'] as List, diff --git a/lib/src/commands/build_command.dart b/lib/src/commands/build_command.dart index 6e56bd2..580e01e 100644 --- a/lib/src/commands/build_command.dart +++ b/lib/src/commands/build_command.dart @@ -25,13 +25,12 @@ class BuildCommand extends Command { AotBuilder Function(Workspace ws, HostInfo host)? aotFactory, BundleBuilder Function(Workspace ws)? bundleFactory, EngineArtifacts Function(Workspace ws)? engineFactory, - }) : _logger = logger, - _host = host, - _loader = loader, - _aotFactory = aotFactory ?? - ((ws, host) => AotBuilder(ws, host: host)), - _bundleFactory = bundleFactory ?? BundleBuilder.new, - _engineFactory = engineFactory ?? EngineArtifacts.new { + }) : _logger = logger, + _host = host, + _loader = loader, + _aotFactory = aotFactory ?? ((ws, host) => AotBuilder(ws, host: host)), + _bundleFactory = bundleFactory ?? BundleBuilder.new, + _engineFactory = engineFactory ?? EngineArtifacts.new { argParser ..addOption( 'workspace', @@ -74,8 +73,10 @@ class BuildCommand extends Command { final args = argResults!; final rest = args.rest; if (rest.isEmpty) { - _logger.err('Usage: emb build ' - '(a dir with emb.yaml or pubspec.yaml emb:)'); + _logger.err( + 'Usage: emb build ' + '(a dir with emb.yaml or pubspec.yaml emb:)', + ); return ExitCode.usage.code; } final host = _host ?? HostInfo.detect(); @@ -84,8 +85,10 @@ class BuildCommand extends Command { final pkgDir = Directory(rest.first); final manifest = _loader.loadPackageDir(pkgDir); if (manifest == null) { - _logger.err('No emb manifest in ${pkgDir.path} ' - '(expected emb.yaml or an emb: key in pubspec.yaml).'); + _logger.err( + 'No emb manifest in ${pkgDir.path} ' + '(expected emb.yaml or an emb: key in pubspec.yaml).', + ); return ExitCode.usage.code; } final build = manifest.build; @@ -96,8 +99,9 @@ class BuildCommand extends Command { // Resolve the matrix: CLI overrides win, else the manifest, else defaults. final appPath = p.normalize(p.join(pkgDir.absolute.path, build.appPath)); - final archs = (args['arch'] as List) - .ifEmpty(build.archs.isEmpty ? [host.machineArch] : build.archs); + final archs = (args['arch'] as List).ifEmpty( + build.archs.isEmpty ? [host.machineArch] : build.archs, + ); final modes = (args['mode'] as List).ifEmpty(build.modes); if (!Directory(appPath).existsSync()) { @@ -105,15 +109,22 @@ class BuildCommand extends Command { return ExitCode.usage.code; } - _logger.info(styleBold.wrap('Building ${manifest.id}: ' - 'archs=${archs.join(",")} modes=${modes.join(",")}')); + _logger.info( + styleBold.wrap( + 'Building ${manifest.id}: ' + 'archs=${archs.join(",")} modes=${modes.join(",")}', + ), + ); var failures = 0; for (final arch in archs) { for (final mode in modes) { final out = build.output != null - ? p.join(workspace.root.path, build.output, - '${manifest.id}-$mode-${EngineArtifacts.engineArch(arch)}') + ? p.join( + workspace.root.path, + build.output, + '${manifest.id}-$mode-${EngineArtifacts.engineArch(arch)}', + ) : defaultBundleOutput(workspace, appPath, mode, arch); final progress = _logger.progress('$mode/$arch'); diff --git a/lib/src/commands/bundle_command.dart b/lib/src/commands/bundle_command.dart index f75b0eb..e9f4282 100644 --- a/lib/src/commands/bundle_command.dart +++ b/lib/src/commands/bundle_command.dart @@ -21,11 +21,10 @@ class BundleCommand extends Command { HostInfo? host, BundleBuilder Function(Workspace ws)? bundleFactory, AotBuilder Function(Workspace ws, HostInfo host)? aotFactory, - }) : _logger = logger, - _host = host, - _bundleFactory = bundleFactory ?? BundleBuilder.new, - _aotFactory = - aotFactory ?? ((ws, host) => AotBuilder(ws, host: host)) { + }) : _logger = logger, + _host = host, + _bundleFactory = bundleFactory ?? BundleBuilder.new, + _aotFactory = aotFactory ?? ((ws, host) => AotBuilder(ws, host: host)) { argParser ..addOption( 'app-path', @@ -53,7 +52,8 @@ class BundleCommand extends Command { 'output', abbr: 'o', aliases: ['out'], - help: 'Output bundle directory, any path (defaults under the ' + help: + 'Output bundle directory, any path (defaults under the ' 'workspace).', ) ..addFlag( @@ -89,7 +89,8 @@ class BundleCommand extends Command { return ExitCode.usage.code; } - final output = (args['output'] as String?) ?? + final output = + (args['output'] as String?) ?? defaultBundleOutput(workspace, appPath, mode, arch); final progress = _logger.progress('Bundle $mode/$arch'); diff --git a/lib/src/commands/deps_command.dart b/lib/src/commands/deps_command.dart index 6daba17..e502086 100644 --- a/lib/src/commands/deps_command.dart +++ b/lib/src/commands/deps_command.dart @@ -19,10 +19,10 @@ class DepsCommand extends Command { HostInfo? host, HostProvisioner Function(HostInfo host)? provisionerFactory, ManifestLoader loader = const ManifestLoader(), - }) : _logger = logger, - _host = host, - _loader = loader, - _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost { + }) : _logger = logger, + _host = host, + _loader = loader, + _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost { argParser ..addMultiOption( 'config', @@ -33,7 +33,8 @@ class DepsCommand extends Command { ..addMultiOption( 'packages', abbr: 'p', - help: 'Directory to discover self-describing emb manifests ' + help: + 'Directory to discover self-describing emb manifests ' '(repeatable).', ) ..addFlag( @@ -76,8 +77,10 @@ class DepsCommand extends Command { } if (manifests.isEmpty) { - _logger.warn('No manifests found. ' - 'Pass --config and/or --packages .'); + _logger.warn( + 'No manifests found. ' + 'Pass --config and/or --packages .', + ); return ExitCode.success.code; } @@ -86,11 +89,15 @@ class DepsCommand extends Command { final coalesced = resolver.coalesce(manifests); _logger - ..info('Host: ${host.os.name}/${host.machineArch} ' - '(${host.hostType} ${host.versionId})') - ..info('Manifests: ${manifests.length}, ' - 'contributing: ${coalesced.byComponent.length}, ' - 'skipped: ${coalesced.skipped.length}') + ..info( + 'Host: ${host.os.name}/${host.machineArch} ' + '(${host.hostType} ${host.versionId})', + ) + ..info( + 'Manifests: ${manifests.length}, ' + 'contributing: ${coalesced.byComponent.length}, ' + 'skipped: ${coalesced.skipped.length}', + ) ..info('Coalesced packages: ${coalesced.packages.length}') ..detail('Cache key: ${coalesced.contentHash}'); @@ -113,21 +120,30 @@ class DepsCommand extends Command { plan.additional.isEmpty && plan.unresolved.isEmpty) { _logger.info( - lightGreen.wrap('All ${coalesced.packages.length} dependencies ' - 'already satisfied.')); + lightGreen.wrap( + 'All ${coalesced.packages.length} dependencies ' + 'already satisfied.', + ), + ); return ExitCode.success.code; } if (plan.toInstall.isNotEmpty) { - _logger.info('Would install (${plan.toInstall.length}): ' - '${plan.toInstall.join(", ")}'); + _logger.info( + 'Would install (${plan.toInstall.length}): ' + '${plan.toInstall.join(", ")}', + ); } if (plan.additional.isNotEmpty) { - _logger.info('Additional deps (${plan.additional.length}): ' - '${plan.additional.join(", ")}'); + _logger.info( + 'Additional deps (${plan.additional.length}): ' + '${plan.additional.join(", ")}', + ); } if (plan.unresolved.isNotEmpty) { - _logger.warn('Unresolved (${plan.unresolved.length}): ' - '${plan.unresolved.join(", ")}'); + _logger.warn( + 'Unresolved (${plan.unresolved.length}): ' + '${plan.unresolved.join(", ")}', + ); } return ExitCode.success.code; } @@ -135,14 +151,19 @@ class DepsCommand extends Command { // ── Filter ────────────────────────────────────────────────────────── final filtered = await resolver.filter(coalesced, provisioner); if (filtered.isSatisfied) { - _logger.info(lightGreen - .wrap('All ${coalesced.packages.length} dependencies already ' - 'satisfied.')); + _logger.info( + lightGreen.wrap( + 'All ${coalesced.packages.length} dependencies already ' + 'satisfied.', + ), + ); return ExitCode.success.code; } - _logger.info('Missing (${filtered.missing.length}): ' - '${filtered.missing.join(", ")}'); + _logger.info( + 'Missing (${filtered.missing.length}): ' + '${filtered.missing.join(", ")}', + ); if (!(args['yes'] as bool)) { final proceed = _logger.confirm( @@ -156,8 +177,9 @@ class DepsCommand extends Command { } // ── Install (single transaction) ──────────────────────────────────── - final progress = - _logger.progress('Installing ${filtered.missing.length} package(s)'); + final progress = _logger.progress( + 'Installing ${filtered.missing.length} package(s)', + ); final result = await provisioner.install( filtered.missing.toSet(), onProgress: (p) => progress.update( diff --git a/lib/src/commands/doctor_command.dart b/lib/src/commands/doctor_command.dart index 5b78c58..4cab50f 100644 --- a/lib/src/commands/doctor_command.dart +++ b/lib/src/commands/doctor_command.dart @@ -13,9 +13,9 @@ class DoctorCommand extends Command { required Logger logger, HostInfo? host, HostProvisioner Function(HostInfo host)? provisionerFactory, - }) : _logger = logger, - _host = host, - _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost; + }) : _logger = logger, + _host = host, + _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost; final Logger _logger; final HostInfo? _host; @@ -35,8 +35,10 @@ class DoctorCommand extends Command { _logger ..info(styleBold.wrap('Host')) ..info(' os: ${host.os.name}') - ..info(' arch: ${host.machineArch} (flutter: ${host.flutterArch}, ' - 'engine: ${EngineArtifacts.engineArchForHost(host)})') + ..info( + ' arch: ${host.machineArch} (flutter: ${host.flutterArch}, ' + 'engine: ${EngineArtifacts.engineArchForHost(host)})', + ) ..info(' host type: ${host.hostType}') ..info(' version: ${host.versionId}'); if (host.prettyName != null) { diff --git a/lib/src/commands/engine_command.dart b/lib/src/commands/engine_command.dart index a9a49f2..f7d17a5 100644 --- a/lib/src/commands/engine_command.dart +++ b/lib/src/commands/engine_command.dart @@ -18,9 +18,9 @@ class EngineCommand extends Command { required Logger logger, HostInfo? host, EngineArtifacts Function(Workspace ws)? engineFactory, - }) : _logger = logger, - _host = host, - _engineFactory = engineFactory ?? EngineArtifacts.new { + }) : _logger = logger, + _host = host, + _engineFactory = engineFactory ?? EngineArtifacts.new { argParser ..addOption( 'workspace', @@ -29,7 +29,8 @@ class EngineCommand extends Command { ) ..addOption( 'commit', - help: 'Engine commit (defaults to ' + help: + 'Engine commit (defaults to ' '/flutter/bin/internal/engine.version).', ) ..addOption( @@ -39,7 +40,8 @@ class EngineCommand extends Command { ..addMultiOption( 'mode', abbr: 'm', - help: 'Runtime modes to fetch (others are auto-fetched on demand by ' + help: + 'Runtime modes to fetch (others are auto-fetched on demand by ' '`emb bundle`/`build`).', allowed: engineRuntimeModes, defaultsTo: const ['release'], @@ -73,12 +75,13 @@ class EngineCommand extends Command { final host = _host ?? HostInfo.detect(); final workspace = Workspace.resolve(override: args['workspace'] as String?); - final commit = - (args['commit'] as String?) ?? workspace.engineCommit(); + final commit = (args['commit'] as String?) ?? workspace.engineCommit(); if (commit == null || commit.isEmpty) { - _logger.err('Could not determine the engine commit. ' - 'Provide --commit or ensure ' - '${workspace.flutterDir.path}/bin/internal/engine.version exists.'); + _logger.err( + 'Could not determine the engine commit. ' + 'Provide --commit or ensure ' + '${workspace.flutterDir.path}/bin/internal/engine.version exists.', + ); return ExitCode.usage.code; } // Determine the proper engine SDK arch token for this machine (or honor @@ -88,8 +91,10 @@ class EngineCommand extends Command { ); final modes = args['mode'] as List; - _logger.info('Engine commit: $commit arch: $arch ' - '(host: ${host.machineArch}) modes: ${modes.join(", ")}'); + _logger.info( + 'Engine commit: $commit arch: $arch ' + '(host: ${host.machineArch}) modes: ${modes.join(", ")}', + ); final engine = _engineFactory(workspace); var anyBuildNeeded = false; @@ -131,10 +136,12 @@ class EngineCommand extends Command { if (anyBuildNeeded) { _logger ..info('') - ..warn('One or more modes have no published prebuilt. ' + ..warn( + 'One or more modes have no published prebuilt. ' 'Source-build (gclient + gn + autoninja) is not yet implemented in ' 'emb — run the legacy flutter_workspace.py engine build, or build ' - 'from meta-flutter/flutter-engine, for now.'); + 'from meta-flutter/flutter-engine, for now.', + ); return ExitCode.unavailable.code; } return ExitCode.success.code; diff --git a/lib/src/commands/env_command.dart b/lib/src/commands/env_command.dart index 4e105fe..1b6a557 100644 --- a/lib/src/commands/env_command.dart +++ b/lib/src/commands/env_command.dart @@ -14,8 +14,8 @@ import 'package:path/path.dart' as p; class EnvCommand extends Command { /// {@macro env_command} EnvCommand({required Logger logger, HostInfo? host}) - : _logger = logger, - _host = host { + : _logger = logger, + _host = host { argParser ..addOption( 'workspace', @@ -61,7 +61,8 @@ class EnvCommand extends Command { return ExitCode.success.code; } - final out = (args['output'] as String?) ?? + final out = + (args['output'] as String?) ?? p.join(workspace.root.path, 'setup_env.sh'); File(out).writeAsStringSync(script); _logger diff --git a/lib/src/commands/flutter_command.dart b/lib/src/commands/flutter_command.dart index 89ff368..32f04c1 100644 --- a/lib/src/commands/flutter_command.dart +++ b/lib/src/commands/flutter_command.dart @@ -19,10 +19,9 @@ class FlutterCommand extends Command { required Logger logger, HostInfo? host, FlutterSdk Function(Workspace ws, HostInfo host)? sdkFactory, - }) : _logger = logger, - _host = host, - _sdkFactory = sdkFactory ?? - ((ws, host) => FlutterSdk(ws, host: host)) { + }) : _logger = logger, + _host = host, + _sdkFactory = sdkFactory ?? ((ws, host) => FlutterSdk(ws, host: host)) { argParser ..addOption( 'workspace', @@ -31,7 +30,8 @@ class FlutterCommand extends Command { ) ..addOption( 'flutter-version', - help: 'Flutter version/tag/branch to check out. Defaults to ' + help: + 'Flutter version/tag/branch to check out. Defaults to ' "globals.json's flutter_version.", ) ..addMultiOption( @@ -42,7 +42,8 @@ class FlutterCommand extends Command { ) ..addFlag( 'configure', - help: 'Run `flutter config` (desktop + custom devices) and ' + help: + 'Run `flutter config` (desktop + custom devices) and ' '`flutter doctor` after install.', negatable: false, ); @@ -53,8 +54,7 @@ class FlutterCommand extends Command { final FlutterSdk Function(Workspace ws, HostInfo host) _sdkFactory; @override - String get description => - 'Install the Flutter SDK into /flutter.'; + String get description => 'Install the Flutter SDK into /flutter.'; @override String get name => 'flutter'; @@ -65,18 +65,22 @@ class FlutterCommand extends Command { final host = _host ?? HostInfo.detect(); final workspace = Workspace.resolve(override: args['workspace'] as String?); - final version = (args['flutter-version'] as String?) ?? + final version = + (args['flutter-version'] as String?) ?? _versionFromGlobals(args['config'] as List); if (version == null || version.isEmpty) { - _logger.err('No Flutter version. Pass --flutter-version or provide a ' - 'globals.json with "flutter_version" via --config.'); + _logger.err( + 'No Flutter version. Pass --flutter-version or provide a ' + 'globals.json with "flutter_version" via --config.', + ); return ExitCode.usage.code; } final sdk = _sdkFactory(workspace, host); - final progress = - _logger.progress('Installing Flutter SDK $version into ' - '${workspace.flutterDir.path}'); + final progress = _logger.progress( + 'Installing Flutter SDK $version into ' + '${workspace.flutterDir.path}', + ); final result = await sdk.install(version); if (!result.success) { progress.fail('Flutter SDK install failed'); diff --git a/lib/src/commands/setup_command.dart b/lib/src/commands/setup_command.dart index a59d87f..86f8a1c 100644 --- a/lib/src/commands/setup_command.dart +++ b/lib/src/commands/setup_command.dart @@ -30,40 +30,63 @@ class SetupCommand extends Command { HostProvisioner Function(HostInfo host)? provisionerFactory, FlutterSdk Function(Workspace ws, HostInfo host)? sdkFactory, EngineArtifacts Function(Workspace ws)? engineFactory, - }) : _logger = logger, - _host = host, - _loader = loader, - _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost, - _sdkFactory = - sdkFactory ?? ((ws, host) => FlutterSdk(ws, host: host)), - _engineFactory = engineFactory ?? EngineArtifacts.new { + }) : _logger = logger, + _host = host, + _loader = loader, + _provisionerFactory = provisionerFactory ?? HostProvisioner.forHost, + _sdkFactory = sdkFactory ?? ((ws, host) => FlutterSdk(ws, host: host)), + _engineFactory = engineFactory ?? EngineArtifacts.new { argParser - ..addMultiOption('config', - abbr: 'c', - help: 'Legacy JSON config directory.', - defaultsTo: const ['configs']) - ..addMultiOption('packages', - abbr: 'p', help: 'Directory to discover self-describing manifests.') - ..addOption('workspace', - abbr: 'w', - help: r'Workspace root (defaults to $FLUTTER_WORKSPACE or cwd).') - ..addOption('flutter-version', - help: "Flutter version (defaults to globals.json's flutter_version).") + ..addMultiOption( + 'config', + abbr: 'c', + help: 'Legacy JSON config directory.', + defaultsTo: const ['configs'], + ) + ..addMultiOption( + 'packages', + abbr: 'p', + help: 'Directory to discover self-describing manifests.', + ) + ..addOption( + 'workspace', + abbr: 'w', + help: r'Workspace root (defaults to $FLUTTER_WORKSPACE or cwd).', + ) + ..addOption( + 'flutter-version', + help: "Flutter version (defaults to globals.json's flutter_version).", + ) ..addOption('arch', help: 'Engine arch (defaults to host).') - ..addMultiOption('mode', - abbr: 'm', - help: 'Engine runtime modes to prefetch.', - allowed: engineRuntimeModes, - defaultsTo: const ['release']) - ..addFlag('yes', - abbr: 'y', help: 'Skip the deps confirmation.', negatable: false) - ..addFlag('skip-deps', help: 'Skip host dependency install.', - negatable: false) + ..addMultiOption( + 'mode', + abbr: 'm', + help: 'Engine runtime modes to prefetch.', + allowed: engineRuntimeModes, + defaultsTo: const ['release'], + ) + ..addFlag( + 'yes', + abbr: 'y', + help: 'Skip the deps confirmation.', + negatable: false, + ) + ..addFlag( + 'skip-deps', + help: 'Skip host dependency install.', + negatable: false, + ) ..addFlag('skip-sync', help: 'Skip repository sync.', negatable: false) - ..addFlag('skip-flutter', help: 'Skip Flutter SDK install.', - negatable: false) - ..addFlag('skip-engine', help: 'Skip engine artifact fetch.', - negatable: false); + ..addFlag( + 'skip-flutter', + help: 'Skip Flutter SDK install.', + negatable: false, + ) + ..addFlag( + 'skip-engine', + help: 'Skip engine artifact fetch.', + negatable: false, + ); } final Logger _logger; @@ -95,8 +118,12 @@ class SetupCommand extends Command { manifests.addAll(_loader.discoverPackages(Directory(dir))); } - _logger.info(styleBold.wrap('emb setup → ${workspace.root.path} ' - '(${host.os.name}/${host.machineArch})')); + _logger.info( + styleBold.wrap( + 'emb setup → ${workspace.root.path} ' + '(${host.os.name}/${host.machineArch})', + ), + ); workspace.ensureAppDir(); if (!(args['skip-deps'] as bool)) { @@ -128,11 +155,13 @@ class SetupCommand extends Command { // Emit setup_env.sh so the workspace's Flutter/Dart are on PATH. final envFile = File(p.join(workspace.root.path, 'setup_env.sh')) - ..writeAsStringSync(generateSetupEnv( - workspace: workspace, - host: host, - engineVersion: workspace.engineCommit(), - )); + ..writeAsStringSync( + generateSetupEnv( + workspace: workspace, + host: host, + engineVersion: workspace.engineCommit(), + ), + ); _logger ..info(lightGreen.wrap('emb setup complete.')) @@ -164,8 +193,10 @@ class SetupCommand extends Command { } _logger.info(' Missing (${missing.length}): ${missing.join(", ")}'); if (!yes && - !_logger.confirm(' Install ${missing.length} package(s)?', - defaultValue: true)) { + !_logger.confirm( + ' Install ${missing.length} package(s)?', + defaultValue: true, + )) { _logger.info(' Skipped.'); return ExitCode.success.code; } @@ -200,8 +231,10 @@ class SetupCommand extends Command { final results = await const RepoSyncer().syncAll( repos, workspace.appDir, - onResult: (r) => progress.update(' [${++done}/${repos.length}] ' - '${r.folderName}${r.success ? "" : " FAILED"}'), + onResult: (r) => progress.update( + ' [${++done}/${repos.length}] ' + '${r.folderName}${r.success ? "" : " FAILED"}', + ), ); final failed = results.where((r) => !r.success).toList(); if (failed.isEmpty) { @@ -224,8 +257,10 @@ class SetupCommand extends Command { _logger.info(styleBold.wrap('▸ Flutter SDK')); final resolved = version ?? _versionFromGlobals(configDirs); if (resolved == null || resolved.isEmpty) { - _logger.err(' No Flutter version: set --flutter-version or ' - 'globals.json.'); + _logger.err( + ' No Flutter version: set --flutter-version or ' + 'globals.json.', + ); return ExitCode.usage.code; } final progress = _logger.progress(' Installing Flutter SDK $resolved'); @@ -236,8 +271,10 @@ class SetupCommand extends Command { return ExitCode.software.code; } final commit = result.engineCommit; - progress.complete(' Flutter SDK $resolved' - '${commit != null ? " (engine $commit)" : ""}'); + progress.complete( + ' Flutter SDK $resolved' + '${commit != null ? " (engine $commit)" : ""}', + ); return ExitCode.success.code; } @@ -259,8 +296,11 @@ class SetupCommand extends Command { try { for (final mode in modes) { final progress = _logger.progress(' Engine $mode'); - final r = - await engine.fetch(runtime: mode, arch: token, commit: commit); + final r = await engine.fetch( + runtime: mode, + arch: token, + commit: commit, + ); switch (r.status) { case EngineFetchStatus.fetched: case EngineFetchStatus.upToDate: diff --git a/lib/src/commands/sync_command.dart b/lib/src/commands/sync_command.dart index 4257df6..8589f9f 100644 --- a/lib/src/commands/sync_command.dart +++ b/lib/src/commands/sync_command.dart @@ -20,8 +20,8 @@ class SyncCommand extends Command { SyncCommand({ required Logger logger, ManifestLoader loader = const ManifestLoader(), - }) : _logger = logger, - _loader = loader { + }) : _logger = logger, + _loader = loader { argParser ..addMultiOption( 'config', @@ -36,7 +36,8 @@ class SyncCommand extends Command { ) ..addMultiOption( 'repos', - help: 'A JSON file containing a bare array of repo entries ' + help: + 'A JSON file containing a bare array of repo entries ' '(repeatable).', ) ..addOption( @@ -65,8 +66,7 @@ class SyncCommand extends Command { @override Future run() async { final args = argResults!; - final workspace = - Workspace.resolve(override: args['workspace'] as String?); + final workspace = Workspace.resolve(override: args['workspace'] as String?); // Collect repos from manifests' `src` lists. final manifests = []; @@ -95,13 +95,14 @@ class SyncCommand extends Command { return ExitCode.success.code; } - final concurrency = - int.tryParse(args['concurrency'] as String) ?? 4; + final concurrency = int.tryParse(args['concurrency'] as String) ?? 4; final appDir = workspace.appDir; _logger ..info('Workspace: ${workspace.root.path}') - ..info('Syncing ${unique.length} repo(s) into ${appDir.path} ' - '(concurrency: $concurrency)'); + ..info( + 'Syncing ${unique.length} repo(s) into ${appDir.path} ' + '(concurrency: $concurrency)', + ); final progress = _logger.progress('Syncing repositories'); var done = 0; @@ -110,8 +111,10 @@ class SyncCommand extends Command { appDir, onResult: (r) { done++; - progress.update('[$done/${unique.length}] ${r.folderName}' - '${r.success ? "" : " FAILED"}'); + progress.update( + '[$done/${unique.length}] ${r.folderName}' + '${r.success ? "" : " FAILED"}', + ); }, ); diff --git a/lib/src/commands/update_command.dart b/lib/src/commands/update_command.dart index be70fd9..2bc9f28 100644 --- a/lib/src/commands/update_command.dart +++ b/lib/src/commands/update_command.dart @@ -11,11 +11,9 @@ import 'package:pub_updater/pub_updater.dart'; /// {@endtemplate} class UpdateCommand extends Command { /// {@macro update_command} - UpdateCommand({ - required Logger logger, - PubUpdater? pubUpdater, - }) : _logger = logger, - _pubUpdater = pubUpdater ?? PubUpdater(); + UpdateCommand({required Logger logger, PubUpdater? pubUpdater}) + : _logger = logger, + _pubUpdater = pubUpdater ?? PubUpdater(); final Logger _logger; final PubUpdater _pubUpdater; diff --git a/lib/src/engine/engine_artifacts.dart b/lib/src/engine/engine_artifacts.dart index 64b6bf2..ca31682 100644 --- a/lib/src/engine/engine_artifacts.dart +++ b/lib/src/engine/engine_artifacts.dart @@ -55,7 +55,7 @@ class EngineFetchResult { /// layout. class EngineArtifacts { EngineArtifacts(this.workspace, {HttpClient? httpClient}) - : _http = httpClient ?? HttpClient(); + : _http = httpClient ?? HttpClient(); final Workspace workspace; final HttpClient _http; @@ -132,8 +132,9 @@ class EngineArtifacts { ..createSync(recursive: true); final archiveFile = File(p.join(cwdEngine.path, filename)); final sha256File = File('${archiveFile.path}.sha256'); - final bundleDir = - Directory(p.join(engineDir.path, 'bundle-$runtime-$arch')); + final bundleDir = Directory( + p.join(engineDir.path, 'bundle-$runtime-$arch'), + ); // Download unless a verified copy already exists. if (!_sha256Matches(archiveFile, sha256File)) { @@ -160,12 +161,14 @@ class EngineArtifacts { // Extract. final restoreDir = Directory( - p.join(cwdEngine.path, 'engine-sdk-$runtime-$arch')) - ..createSync(recursive: true); - final tar = await Process.run( - 'tar', - ['-xzf', archiveFile.path, '-C', restoreDir.path], - ); + p.join(cwdEngine.path, 'engine-sdk-$runtime-$arch'), + )..createSync(recursive: true); + final tar = await Process.run('tar', [ + '-xzf', + archiveFile.path, + '-C', + restoreDir.path, + ]); if (tar.exitCode != 0) { return EngineFetchResult( runtime: runtime, diff --git a/lib/src/flutter/flutter_sdk.dart b/lib/src/flutter/flutter_sdk.dart index 2b37da5..d7cf6f8 100644 --- a/lib/src/flutter/flutter_sdk.dart +++ b/lib/src/flutter/flutter_sdk.dart @@ -82,20 +82,20 @@ class FlutterSdk { '--enable-custom-devices', ...switch (h.os) { HostOs.linux => [ - '--enable-linux-desktop', - '--no-enable-macos-desktop', - '--no-enable-windows-desktop', - ], + '--enable-linux-desktop', + '--no-enable-macos-desktop', + '--no-enable-windows-desktop', + ], HostOs.macos => [ - '--enable-macos-desktop', - '--no-enable-linux-desktop', - '--no-enable-windows-desktop', - ], + '--enable-macos-desktop', + '--no-enable-linux-desktop', + '--no-enable-windows-desktop', + ], HostOs.windows => [ - '--enable-windows-desktop', - '--no-enable-linux-desktop', - '--no-enable-macos-desktop', - ], + '--enable-windows-desktop', + '--no-enable-linux-desktop', + '--no-enable-macos-desktop', + ], }, ]; final config = await Process.run(flutterBin, args); diff --git a/lib/src/host/host_info.dart b/lib/src/host/host_info.dart index 57c1ccc..1310b4f 100644 --- a/lib/src/host/host_info.dart +++ b/lib/src/host/host_info.dart @@ -14,10 +14,10 @@ enum HostOs { /// non-Linux operating systems. On Linux the distro id is used instead /// (see [HostInfo.hostType]). String get configToken => switch (this) { - HostOs.linux => 'linux', - HostOs.macos => 'darwin', - HostOs.windows => 'windows', - }; + HostOs.linux => 'linux', + HostOs.macos => 'darwin', + HostOs.windows => 'windows', + }; } /// Immutable description of the machine `emb` is executing on. @@ -102,11 +102,11 @@ class HostInfo { /// The Flutter/Google architecture token (`x64`, `arm64`, `aarch64`). /// Mirrors `get_flutter_arch`. String get flutterArch => switch (machineArch) { - 'x86_64' || 'AMD64' || 'x64' => 'x64', - 'arm64' || 'ARM64' => 'arm64', - 'aarch64' => 'arm64', - _ => machineArch, - }; + 'x86_64' || 'AMD64' || 'x64' => 'x64', + 'arm64' || 'ARM64' => 'arm64', + 'aarch64' => 'arm64', + _ => machineArch, + }; /// Whether any of [archs] matches this host's architecture. bool supportsArch(Iterable archs) => @@ -122,7 +122,8 @@ class HostInfo { if (Platform.isMacOS) return HostOs.macos; if (Platform.isWindows) return HostOs.windows; throw UnsupportedError( - 'Unsupported host operating system: ${Platform.operatingSystem}'); + 'Unsupported host operating system: ${Platform.operatingSystem}', + ); } /// Map the FFI [Abi] to the raw machine string the config files use. This @@ -185,7 +186,8 @@ class HostInfo { } @override - String toString() => 'HostInfo(os: ${os.name}, arch: $machineArch, ' + String toString() => + 'HostInfo(os: ${os.name}, arch: $machineArch, ' 'hostType: $hostType, versionId: $versionId)'; } diff --git a/lib/src/manifest/emb_manifest.dart b/lib/src/manifest/emb_manifest.dart index 286d579..60b6c5f 100644 --- a/lib/src/manifest/emb_manifest.dart +++ b/lib/src/manifest/emb_manifest.dart @@ -30,10 +30,7 @@ class EmbManifest { /// Parse a manifest map. Detects structured vs legacy host-dep schemas /// automatically, so both `emb` manifests and legacy `configs/*.json` /// documents flow through one path. - factory EmbManifest.fromMap( - Map map, { - String? sourcePath, - }) { + factory EmbManifest.fromMap(Map map, {String? sourcePath}) { final deps = _parseDeps(map); final srcList = (map['src'] ?? map['repos']) as List? ?? const []; @@ -41,10 +38,12 @@ class EmbManifest { id: (map['id'] ?? '') as String, type: (map['type'] ?? 'app') as String, load: (map['load'] ?? true) as bool, - supportedArchs: - _stringList(map['supported_archs'] ?? map['supportedArchs']), + supportedArchs: _stringList( + map['supported_archs'] ?? map['supportedArchs'], + ), supportedHostTypes: _stringList( - map['supported_host_types'] ?? map['supportedHostTypes']), + map['supported_host_types'] ?? map['supportedHostTypes'], + ), env: _stringMap(map['env']), src: srcList .whereType>() @@ -128,6 +127,7 @@ class EmbManifest { } @override - String toString() => 'EmbManifest($id, type: $type, ' + String toString() => + 'EmbManifest($id, type: $type, ' 'deps: ${deps.rules.length} rules)'; } diff --git a/lib/src/manifest/host_deps.dart b/lib/src/manifest/host_deps.dart index 4e1b760..91d6dcb 100644 --- a/lib/src/manifest/host_deps.dart +++ b/lib/src/manifest/host_deps.dart @@ -45,7 +45,8 @@ class DepRule { } @override - String toString() => 'DepRule(${os.name}' + String toString() => + 'DepRule(${os.name}' '${hostType != null ? "/$hostType" : ""}' '${versionId != null ? "/$versionId" : ""}' '${arch != null ? "@$arch" : ""}: ${packages.join(" ")})'; @@ -79,11 +80,13 @@ class HostDeps { for (final sub in value.entries) { final pkgs = sub.value; if (pkgs is List) { - rules.add(DepRule( - os: os, - hostType: sub.key.toString().toLowerCase(), - packages: _stringList(pkgs), - )); + rules.add( + DepRule( + os: os, + hostType: sub.key.toString().toLowerCase(), + packages: _stringList(pkgs), + ), + ); } } } @@ -110,8 +113,9 @@ class HostDeps { // Distro-level cmds apply to all versions of this distro+arch. final distroPkgs = _packagesFromCmds(distroMap['cmds']); if (distroPkgs.isNotEmpty) { - rules.add(DepRule( - os: os, arch: arch, hostType: distro, packages: distroPkgs)); + rules.add( + DepRule(os: os, arch: arch, hostType: distro, packages: distroPkgs), + ); } // Version-specific nested cmds (keys that are version ids). @@ -122,13 +126,15 @@ class HostDeps { if (versionMap is! Map) continue; final versionPkgs = _packagesFromCmds(versionMap['cmds']); if (versionPkgs.isNotEmpty) { - rules.add(DepRule( - os: os, - arch: arch, - hostType: distro, - versionId: key, - packages: versionPkgs, - )); + rules.add( + DepRule( + os: os, + arch: arch, + hostType: distro, + versionId: key, + packages: versionPkgs, + ), + ); } } } diff --git a/lib/src/manifest/manifest_loader.dart b/lib/src/manifest/manifest_loader.dart index 744e16f..ce3e23e 100644 --- a/lib/src/manifest/manifest_loader.dart +++ b/lib/src/manifest/manifest_loader.dart @@ -19,13 +19,14 @@ class ManifestLoader { /// Skips `globals.json` (workspace globals, not a component). List loadConfigDir(Directory dir) { if (!dir.existsSync()) return const []; - final files = dir - .listSync() - .whereType() - .where((f) => f.path.endsWith('.json')) - .where((f) => p.basename(f.path) != 'globals.json') - .toList() - ..sort((a, b) => a.path.compareTo(b.path)); + final files = + dir + .listSync() + .whereType() + .where((f) => f.path.endsWith('.json')) + .where((f) => p.basename(f.path) != 'globals.json') + .toList() + ..sort((a, b) => a.path.compareTo(b.path)); final out = []; for (final f in files) { final manifest = _tryLoadJson(f); @@ -45,8 +46,10 @@ class ManifestLoader { if (embYaml.existsSync()) { final map = _yamlToMap(loadYaml(embYaml.readAsStringSync())); if (map != null) { - return EmbManifest.fromMap(_withDefaultId(map, dir), - sourcePath: embYaml.path); + return EmbManifest.fromMap( + _withDefaultId(map, dir), + sourcePath: embYaml.path, + ); } } final pubspec = File(p.join(dir.path, 'pubspec.yaml')); @@ -81,9 +84,14 @@ class ManifestLoader { try { final decoded = jsonDecode(file.readAsStringSync()); if (decoded is Map) { - return EmbManifest.fromMap(_withDefaultId(decoded, file.parent, - fallbackId: p.basenameWithoutExtension(file.path)), - sourcePath: file.path); + return EmbManifest.fromMap( + _withDefaultId( + decoded, + file.parent, + fallbackId: p.basenameWithoutExtension(file.path), + ), + sourcePath: file.path, + ); } } on FormatException { // Skip malformed config files rather than aborting the whole load. @@ -108,8 +116,7 @@ class ManifestLoader { dynamic _convertYaml(dynamic node) { if (node is YamlMap) { - return node.map( - (k, v) => MapEntry(k.toString(), _convertYaml(v))); + return node.map((k, v) => MapEntry(k.toString(), _convertYaml(v))); } if (node is YamlList) { return node.map(_convertYaml).toList(); diff --git a/lib/src/pkg/_platform/brew_provisioner.dart b/lib/src/pkg/_platform/brew_provisioner.dart index 1580afd..7700894 100644 --- a/lib/src/pkg/_platform/brew_provisioner.dart +++ b/lib/src/pkg/_platform/brew_provisioner.dart @@ -47,8 +47,7 @@ class BrewProvisioner implements HostProvisioner { final batch = await _brew.installAll( toGet.toList(), parallel: true, - onEach: (pkg, result) => - onProgress?.call(ProvisionProgress(label: pkg)), + onEach: (pkg, result) => onProgress?.call(ProvisionProgress(label: pkg)), ); _installedCache = null; // invalidate after mutation return ProvisionResult( diff --git a/lib/src/pkg/_platform/winget_provisioner.dart b/lib/src/pkg/_platform/winget_provisioner.dart index 701bdb5..05173bc 100644 --- a/lib/src/pkg/_platform/winget_provisioner.dart +++ b/lib/src/pkg/_platform/winget_provisioner.dart @@ -84,9 +84,11 @@ class WingetProvisioner implements HostProvisioner { final failed = []; for (final id in toGet) { final tx = client.installPackage(id); - final sub = tx.progress.listen((p) => onProgress?.call( - ProvisionProgress(label: '$id ${p.label}', percent: p.percent), - )); + final sub = tx.progress.listen( + (p) => onProgress?.call( + ProvisionProgress(label: '$id ${p.label}', percent: p.percent), + ), + ); try { await tx.result; installed.add(id); diff --git a/lib/src/pkg/packagekit_provisioner.dart b/lib/src/pkg/packagekit_provisioner.dart index 256d166..291818a 100644 --- a/lib/src/pkg/packagekit_provisioner.dart +++ b/lib/src/pkg/packagekit_provisioner.dart @@ -44,8 +44,9 @@ class PackageKitProvisioner implements HostProvisioner { final client = await _connect(); // A name is satisfied if an installed package matches it directly, or if // an installed package *provides* it. - final installedByName = - await _resolveNames(client, names.toList(), const [PkFilter.installed]); + final installedByName = await _resolveNames(client, names.toList(), const [ + PkFilter.installed, + ]); final satisfied = installedByName.keys.toSet(); for (final n in names.difference(satisfied)) { if (await _providesInstalled(client, n)) satisfied.add(n); @@ -98,7 +99,8 @@ class PackageKitProvisioner implements HostProvisioner { return ProvisionResult( installed: const [], failed: res.unresolved, - message: 'No installable packages found for: ' + message: + 'No installable packages found for: ' '${res.unresolved.join(", ")}', ); } @@ -108,10 +110,12 @@ class PackageKitProvisioner implements HostProvisioner { final label = p.packageId.isNotEmpty ? p.packageId.split(';').first : p.status.name; - onProgress?.call(ProvisionProgress( - label: label, - percent: p.percentageKnown ? p.percentage : null, - )); + onProgress?.call( + ProvisionProgress( + label: label, + percent: p.percentageKnown ? p.percentage : null, + ), + ); }); final errors = []; final errSub = tx.errors.listen((e) => errors.add(e.details)); @@ -176,8 +180,11 @@ class PackageKitProvisioner implements HostProvisioner { PkClient client, Set names, ) async { - final byName = - await _resolveNames(client, names.toList(), _installableFilters); + final byName = await _resolveNames( + client, + names.toList(), + _installableFilters, + ); final ids = {...byName.values}; final unresolved = []; diff --git a/lib/src/pkg/provision_models.dart b/lib/src/pkg/provision_models.dart index ccd6b67..478d7b0 100644 --- a/lib/src/pkg/provision_models.dart +++ b/lib/src/pkg/provision_models.dart @@ -9,8 +9,10 @@ class ProvisionPlan { }); /// An empty plan (nothing to do). - static const ProvisionPlan empty = - ProvisionPlan(requested: [], toInstall: []); + static const ProvisionPlan empty = ProvisionPlan( + requested: [], + toInstall: [], + ); /// The package names that were requested. final List requested; diff --git a/lib/src/repo/git_repo.dart b/lib/src/repo/git_repo.dart index 7e07f0f..1360da0 100644 --- a/lib/src/repo/git_repo.dart +++ b/lib/src/repo/git_repo.dart @@ -4,17 +4,17 @@ import 'package:emb_cli/src/manifest/source_repo.dart'; import 'package:path/path.dart' as p; /// Runs a git subcommand in [workingDirectory]. Injectable for testing. -typedef GitRunner = Future Function( - List args, { - required String workingDirectory, -}); +typedef GitRunner = + Future Function( + List args, { + required String workingDirectory, + }); /// Default [GitRunner] backed by `Process.run`. Future defaultGitRunner( List args, { required String workingDirectory, -}) => - Process.run('git', args, workingDirectory: workingDirectory); +}) => Process.run('git', args, workingDirectory: workingDirectory); /// The outcome of syncing a single repository. class RepoResult { @@ -37,19 +37,10 @@ class RepoResult { /// otherwise `reset --hard` + `fetch --all` + `pull --ff-only`; then checkout /// the requested rev/branch and fetch LFS objects and submodules when present. class GitRepo { - const GitRepo({ - required this.uri, - this.branch, - this.rev, - this.destName, - }); + const GitRepo({required this.uri, this.branch, this.rev, this.destName}); - factory GitRepo.fromSource(SourceRepo s) => GitRepo( - uri: s.uri, - branch: s.branch, - rev: s.rev, - destName: s.destName, - ); + factory GitRepo.fromSource(SourceRepo s) => + GitRepo(uri: s.uri, branch: s.branch, rev: s.rev, destName: s.destName); final String uri; final String? branch; @@ -88,11 +79,12 @@ class GitRepo { if (Directory(gitFolder).existsSync()) { Directory(gitFolder).deleteSync(recursive: true); } - await _run( - runner, - ['clone', uri, folderName, if (branch != null) ...['-b', branch!]], - base, - ); + await _run(runner, [ + 'clone', + uri, + folderName, + if (branch != null) ...['-b', branch!], + ], base); } if (rev != null) { @@ -102,16 +94,21 @@ class GitRepo { } if (File(p.join(gitFolder, '.gitattributes')).existsSync()) { - await _run(runner, ['lfs', 'fetch', '--all'], gitFolder, - allowFailure: true); - } - if (File(p.join(gitFolder, '.gitmodules')).existsSync()) { await _run( runner, - ['submodule', 'update', '--init', '--recursive'], + ['lfs', 'fetch', '--all'], gitFolder, + allowFailure: true, ); } + if (File(p.join(gitFolder, '.gitmodules')).existsSync()) { + await _run(runner, [ + 'submodule', + 'update', + '--init', + '--recursive', + ], gitFolder); + } return RepoResult(folderName: folderName, uri: uri, success: true); } on _GitException catch (e) { @@ -133,7 +130,8 @@ class GitRepo { final r = await runner(args, workingDirectory: cwd); if (r.exitCode != 0 && !allowFailure) { throw _GitException( - 'git ${args.join(" ")} failed (${r.exitCode}): ${r.stderr}'); + 'git ${args.join(" ")} failed (${r.exitCode}): ${r.stderr}', + ); } } } diff --git a/lib/src/repo/repo_syncer.dart b/lib/src/repo/repo_syncer.dart index a70dc8e..626d5ac 100644 --- a/lib/src/repo/repo_syncer.dart +++ b/lib/src/repo/repo_syncer.dart @@ -36,9 +36,7 @@ class RepoSyncer { } final workerCount = concurrency < 1 ? 1 : concurrency; - await Future.wait( - List.generate(workerCount, (_) => worker()), - ); + await Future.wait(List.generate(workerCount, (_) => worker())); return results; } } diff --git a/lib/src/workspace/workspace.dart b/lib/src/workspace/workspace.dart index 9be4f7a..566c114 100644 --- a/lib/src/workspace/workspace.dart +++ b/lib/src/workspace/workspace.dart @@ -19,7 +19,8 @@ class Workspace { /// current working directory). factory Workspace.resolve({String? override, Directory? fallback}) { final envPath = Platform.environment['FLUTTER_WORKSPACE']; - final path = override ?? + final path = + override ?? (envPath != null && envPath.isNotEmpty ? envPath : null) ?? (fallback ?? Directory.current).path; return Workspace(Directory(p.normalize(p.absolute(path)))); @@ -55,8 +56,9 @@ class Workspace { /// `get_flutter_engine_version` / `get_flutter_engine_commit`. Returns null /// when the SDK (or the file) is absent. String? engineCommit() { - final f = - File(p.join(flutterDir.path, 'bin', 'internal', 'engine.version')); + final f = File( + p.join(flutterDir.path, 'bin', 'internal', 'engine.version'), + ); if (!f.existsSync()) return null; final v = f.readAsStringSync().trim(); return v.isEmpty ? null : v; diff --git a/test/src/aot/aot_builder_test.dart b/test/src/aot/aot_builder_test.dart index 7d1e087..4c1ceaa 100644 --- a/test/src/aot/aot_builder_test.dart +++ b/test/src/aot/aot_builder_test.dart @@ -30,8 +30,9 @@ class _Recorder { calls.add((exe: p.basename(exe), args: args)); if (args.isNotEmpty && args.first == 'build') { // Materialise .dart_tool/flutter_build// as flutter would. - Directory(p.join(app, '.dart_tool', 'flutter_build', 'abc123')) - .createSync(recursive: true); + Directory( + p.join(app, '.dart_tool', 'flutter_build', 'abc123'), + ).createSync(recursive: true); } return 0; } @@ -55,15 +56,32 @@ void main() { // Create a fake new-scheme SDK cache so the builder picks dartaotruntime + // frontend_server_aot and finds a host gen_snapshot. void writeSdk(Directory ws) { - final hostEngine = p.join(ws.path, 'flutter', 'bin', 'cache', 'artifacts', - 'engine', 'linux-x64'); + final hostEngine = p.join( + ws.path, + 'flutter', + 'bin', + 'cache', + 'artifacts', + 'engine', + 'linux-x64', + ); Directory(hostEngine).createSync(recursive: true); - File(p.join(hostEngine, 'frontend_server_aot.dart.snapshot')) - .writeAsStringSync('x'); + File( + p.join(hostEngine, 'frontend_server_aot.dart.snapshot'), + ).writeAsStringSync('x'); File(p.join(hostEngine, 'gen_snapshot')).writeAsStringSync('x'); - Directory(p.join(ws.path, 'flutter', 'bin', 'cache', 'artifacts', 'engine', - 'common', 'flutter_patched_sdk_product')) - .createSync(recursive: true); + Directory( + p.join( + ws.path, + 'flutter', + 'bin', + 'cache', + 'artifacts', + 'engine', + 'common', + 'flutter_patched_sdk_product', + ), + ).createSync(recursive: true); } test('runs build → kernel snapshot → gen_snapshot per mode', () async { @@ -73,10 +91,10 @@ void main() { writeSdk(ws); final rec = _Recorder(app.path); - final result = await builder(ws, rec).build( - appPath: app.path, - modes: const ['release'], - ); + final result = await builder( + ws, + rec, + ).build(appPath: app.path, modes: const ['release']); expect(result.success, isTrue); final exes = rec.calls.map((c) => c.exe).toList(); @@ -94,19 +112,24 @@ void main() { final kernel = rec.calls.firstWhere((c) => c.exe == 'dartaotruntime'); expect(kernel.args, contains('-Ddart.vm.product=true')); expect(kernel.args, contains('package:myapp/main.dart')); - expect(kernel.args.any((a) => a.contains('flutter_patched_sdk_product')), - isTrue); + expect( + kernel.args.any((a) => a.contains('flutter_patched_sdk_product')), + isTrue, + ); }); test('fails cleanly when pubspec has no name', () async { final ws = Directory(p.join(tmp.path, 'ws'))..createSync(); final app = Directory(p.join(tmp.path, 'app'))..createSync(); - File(p.join(app.path, 'pubspec.yaml')) - .writeAsStringSync('description: x\n'); + File( + p.join(app.path, 'pubspec.yaml'), + ).writeAsStringSync('description: x\n'); writeSdk(ws); - final result = - await builder(ws, _Recorder(app.path)).build(appPath: app.path); + final result = await builder( + ws, + _Recorder(app.path), + ).build(appPath: app.path); expect(result.success, isFalse); }); } diff --git a/test/src/bundle/bundle_builder_test.dart b/test/src/bundle/bundle_builder_test.dart index 3a59b11..5bb4c67 100644 --- a/test/src/bundle/bundle_builder_test.dart +++ b/test/src/bundle/bundle_builder_test.dart @@ -25,8 +25,15 @@ void main() { File(p.join(app.path, 'libapp.so.release')).writeAsStringSync('APP'); // Engine half: bundle-release-x86_64/{data/icudtl.dat,lib/libflutter_engine.so} - final eng = Directory(p.join(ws.path, '.config', 'flutter_workspace', - 'flutter-engine', 'bundle-release-x86_64')); + final eng = Directory( + p.join( + ws.path, + '.config', + 'flutter_workspace', + 'flutter-engine', + 'bundle-release-x86_64', + ), + ); File(p.join(eng.path, 'data', 'icudtl.dat')) ..createSync(recursive: true) ..writeAsStringSync('ICU'); @@ -51,8 +58,9 @@ void main() { expect(result.success, isTrue); expect(result.outputDir, out); expect( - File(p.join(out, 'data', 'flutter_assets', 'fonts', 'MaterialIcons.ttf')) - .existsSync(), + File( + p.join(out, 'data', 'flutter_assets', 'fonts', 'MaterialIcons.ttf'), + ).existsSync(), isTrue, ); expect(File(p.join(out, 'data', 'icudtl.dat')).existsSync(), isTrue); @@ -63,8 +71,9 @@ void main() { ); // AOT (release): the JIT kernel is stripped — the app runs from libapp.so. expect( - File(p.join(out, 'data', 'flutter_assets', 'kernel_blob.bin')) - .existsSync(), + File( + p.join(out, 'data', 'flutter_assets', 'kernel_blob.bin'), + ).existsSync(), isFalse, ); }); @@ -73,8 +82,15 @@ void main() { final s = stageInputs(); // Remove the AOT lib and stage a debug engine bundle instead. File(p.join(s.app.path, 'libapp.so.release')).deleteSync(); - final eng = Directory(p.join(s.ws.path, '.config', 'flutter_workspace', - 'flutter-engine', 'bundle-debug-x86_64')); + final eng = Directory( + p.join( + s.ws.path, + '.config', + 'flutter_workspace', + 'flutter-engine', + 'bundle-debug-x86_64', + ), + ); File(p.join(eng.path, 'data', 'icudtl.dat')) ..createSync(recursive: true) ..writeAsStringSync('ICU'); @@ -93,13 +109,16 @@ void main() { expect(result.success, isTrue); // flutter_assets + engine present; libapp.so absent (JIT runs kernel_blob). expect(File(p.join(out, 'data', 'icudtl.dat')).existsSync(), isTrue); - expect(File(p.join(out, 'lib', 'libflutter_engine.so')).existsSync(), - isTrue); + expect( + File(p.join(out, 'lib', 'libflutter_engine.so')).existsSync(), + isTrue, + ); expect(File(p.join(out, 'lib', 'libapp.so')).existsSync(), isFalse); // debug keeps kernel_blob.bin (it's what the JIT engine runs). expect( - File(p.join(out, 'data', 'flutter_assets', 'kernel_blob.bin')) - .existsSync(), + File( + p.join(out, 'data', 'flutter_assets', 'kernel_blob.bin'), + ).existsSync(), isTrue, ); }); @@ -107,10 +126,23 @@ void main() { test('maps arch token to the engine bundle dir (arm64)', () { final s = stageInputs(); // Rename engine dir to the arm64 token to prove arch mapping is used. - Directory(p.join(s.ws.path, '.config', 'flutter_workspace', - 'flutter-engine', 'bundle-release-x86_64')) - .renameSync(p.join(s.ws.path, '.config', 'flutter_workspace', - 'flutter-engine', 'bundle-release-arm64')); + Directory( + p.join( + s.ws.path, + '.config', + 'flutter_workspace', + 'flutter-engine', + 'bundle-release-x86_64', + ), + ).renameSync( + p.join( + s.ws.path, + '.config', + 'flutter_workspace', + 'flutter-engine', + 'bundle-release-arm64', + ), + ); final result = BundleBuilder(Workspace(s.ws)).assemble( appPath: s.app.path, diff --git a/test/src/command_runner_test.dart b/test/src/command_runner_test.dart index d9d2a9e..4752d43 100644 --- a/test/src/command_runner_test.dart +++ b/test/src/command_runner_test.dart @@ -17,7 +17,8 @@ class _MockPubUpdater extends Mock implements PubUpdater {} const latestVersion = '0.0.0'; -final updatePrompt = ''' +final updatePrompt = + ''' ${lightYellow.wrap('Update available!')} ${lightCyan.wrap(packageVersion)} \u2192 ${lightCyan.wrap(latestVersion)} Run ${lightCyan.wrap('$executableName update')} to update'''; @@ -52,19 +53,16 @@ void main() { verify(() => logger.info(updatePrompt)).called(1); }); - test( - 'Does not show update message when the shell calls the ' - 'completion command', - () async { - when( - () => pubUpdater.getLatestVersion(any()), - ).thenAnswer((_) async => latestVersion); + test('Does not show update message when the shell calls the ' + 'completion command', () async { + when( + () => pubUpdater.getLatestVersion(any()), + ).thenAnswer((_) async => latestVersion); - final result = await commandRunner.run(['completion']); - expect(result, equals(ExitCode.success.code)); - verifyNever(() => logger.info(updatePrompt)); - }, - ); + final result = await commandRunner.run(['completion']); + expect(result, equals(ExitCode.success.code)); + verifyNever(() => logger.info(updatePrompt)); + }); test('does not show update message when using update command', () async { when( @@ -98,12 +96,14 @@ void main() { verifyNever(() => logger.info(updatePrompt)); }); - test('can be instantiated without an explicit analytics/logger instance', - () { - final commandRunner = EmbCliCommandRunner(); - expect(commandRunner, isNotNull); - expect(commandRunner, isA>()); - }); + test( + 'can be instantiated without an explicit analytics/logger instance', + () { + final commandRunner = EmbCliCommandRunner(); + expect(commandRunner, isNotNull); + expect(commandRunner, isA>()); + }, + ); test('handles FormatException', () async { const exception = FormatException('oops!'); @@ -158,10 +158,7 @@ void main() { final progress = _MockProgress(); when(() => logger.progress(any())).thenReturn(progress); - final result = await commandRunner.run([ - '--verbose', - 'update', - ]); + final result = await commandRunner.run(['--verbose', 'update']); expect(result, equals(ExitCode.success.code)); verify(() => logger.detail('Argument information:')).called(1); diff --git a/test/src/commands/setup_command_test.dart b/test/src/commands/setup_command_test.dart index b58bf04..680c3c1 100644 --- a/test/src/commands/setup_command_test.dart +++ b/test/src/commands/setup_command_test.dart @@ -39,9 +39,10 @@ class _FakeProvisioner implements HostProvisioner { Future simulate(Set names) async => ProvisionPlan(requested: names.toList(), toInstall: const []); @override - Future install(Set names, - {void Function(ProvisionProgress)? onProgress}) async => - ProvisionResult(installed: names.toList()); + Future install( + Set names, { + void Function(ProvisionProgress)? onProgress, + }) async => ProvisionResult(installed: names.toList()); @override Future dispose() async {} } @@ -58,11 +59,13 @@ void main() { CommandRunner runnerWith(_FakeProvisioner prov) { final runner = CommandRunner('emb', 't') - ..addCommand(SetupCommand( - logger: logger, - host: _host, - provisionerFactory: (_) => prov, - )); + ..addCommand( + SetupCommand( + logger: logger, + host: _host, + provisionerFactory: (_) => prov, + ), + ); return runner; } @@ -77,8 +80,10 @@ void main() { final prov = _FakeProvisioner(); final code = await runnerWith(prov).run([ 'setup', - '--config', tmp.path, - '-w', tmp.path, + '--config', + tmp.path, + '-w', + tmp.path, '--skip-sync', '--skip-flutter', '--skip-engine', @@ -95,8 +100,10 @@ void main() { final prov = _FakeProvisioner(); final code = await runnerWith(prov).run([ 'setup', - '--config', tmp.path, - '-w', tmp.path, + '--config', + tmp.path, + '-w', + tmp.path, '--skip-deps', '--skip-sync', '--skip-flutter', diff --git a/test/src/commands/update_command_test.dart b/test/src/commands/update_command_test.dart index a66a383..27ad05b 100644 --- a/test/src/commands/update_command_test.dart +++ b/test/src/commands/update_command_test.dart @@ -61,49 +61,43 @@ void main() { expect(command, isNotNull); }); - test( - 'handles pub latest version query errors', - () async { - when( - () => pubUpdater.getLatestVersion(any()), - ).thenThrow(Exception('oops')); - final result = await commandRunner.run(['update']); - expect(result, equals(ExitCode.software.code)); - verify(() => logger.progress('Checking for updates')).called(1); - verify(() => logger.err('Exception: oops')); - verifyNever( - () => pubUpdater.update( - packageName: any(named: 'packageName'), - versionConstraint: any(named: 'versionConstraint'), - ), - ); - }, - ); + test('handles pub latest version query errors', () async { + when( + () => pubUpdater.getLatestVersion(any()), + ).thenThrow(Exception('oops')); + final result = await commandRunner.run(['update']); + expect(result, equals(ExitCode.software.code)); + verify(() => logger.progress('Checking for updates')).called(1); + verify(() => logger.err('Exception: oops')); + verifyNever( + () => pubUpdater.update( + packageName: any(named: 'packageName'), + versionConstraint: any(named: 'versionConstraint'), + ), + ); + }); - test( - 'handles pub update errors', - () async { - when( - () => pubUpdater.getLatestVersion(any()), - ).thenAnswer((_) async => latestVersion); - when( - () => pubUpdater.update( - packageName: any(named: 'packageName'), - versionConstraint: any(named: 'versionConstraint'), - ), - ).thenThrow(Exception('oops')); - final result = await commandRunner.run(['update']); - expect(result, equals(ExitCode.software.code)); - verify(() => logger.progress('Checking for updates')).called(1); - verify(() => logger.err('Exception: oops')); - verify( - () => pubUpdater.update( - packageName: any(named: 'packageName'), - versionConstraint: any(named: 'versionConstraint'), - ), - ).called(1); - }, - ); + test('handles pub update errors', () async { + when( + () => pubUpdater.getLatestVersion(any()), + ).thenAnswer((_) async => latestVersion); + when( + () => pubUpdater.update( + packageName: any(named: 'packageName'), + versionConstraint: any(named: 'versionConstraint'), + ), + ).thenThrow(Exception('oops')); + final result = await commandRunner.run(['update']); + expect(result, equals(ExitCode.software.code)); + verify(() => logger.progress('Checking for updates')).called(1); + verify(() => logger.err('Exception: oops')); + verify( + () => pubUpdater.update( + packageName: any(named: 'packageName'), + versionConstraint: any(named: 'versionConstraint'), + ), + ).called(1); + }); test('handles pub update process errors', () async { const error = 'Oh no! Installing this is not possible right now!'; @@ -132,54 +126,48 @@ void main() { ).called(1); }); - test( - 'updates when newer version exists', - () async { - when( - () => pubUpdater.getLatestVersion(any()), - ).thenAnswer((_) async => latestVersion); - when( - () => pubUpdater.update( - packageName: any(named: 'packageName'), - versionConstraint: any(named: 'versionConstraint'), - ), - ).thenAnswer( - (_) async => ProcessResult(0, ExitCode.success.code, null, null), - ); - when(() => logger.progress(any())).thenReturn(_MockProgress()); - final result = await commandRunner.run(['update']); - expect(result, equals(ExitCode.success.code)); - verify(() => logger.progress('Checking for updates')).called(1); - verify(() => logger.progress('Updating to $latestVersion')).called(1); - verify( - () => pubUpdater.update( - packageName: packageName, - versionConstraint: latestVersion, - ), - ).called(1); - }, - ); + test('updates when newer version exists', () async { + when( + () => pubUpdater.getLatestVersion(any()), + ).thenAnswer((_) async => latestVersion); + when( + () => pubUpdater.update( + packageName: any(named: 'packageName'), + versionConstraint: any(named: 'versionConstraint'), + ), + ).thenAnswer( + (_) async => ProcessResult(0, ExitCode.success.code, null, null), + ); + when(() => logger.progress(any())).thenReturn(_MockProgress()); + final result = await commandRunner.run(['update']); + expect(result, equals(ExitCode.success.code)); + verify(() => logger.progress('Checking for updates')).called(1); + verify(() => logger.progress('Updating to $latestVersion')).called(1); + verify( + () => pubUpdater.update( + packageName: packageName, + versionConstraint: latestVersion, + ), + ).called(1); + }); - test( - 'does not update when already on latest version', - () async { - when( - () => pubUpdater.getLatestVersion(any()), - ).thenAnswer((_) async => packageVersion); - when(() => logger.progress(any())).thenReturn(_MockProgress()); - final result = await commandRunner.run(['update']); - expect(result, equals(ExitCode.success.code)); - verify( - () => logger.info('CLI is already at the latest version.'), - ).called(1); - verifyNever(() => logger.progress('Updating to $latestVersion')); - verifyNever( - () => pubUpdater.update( - packageName: any(named: 'packageName'), - versionConstraint: any(named: 'versionConstraint'), - ), - ); - }, - ); + test('does not update when already on latest version', () async { + when( + () => pubUpdater.getLatestVersion(any()), + ).thenAnswer((_) async => packageVersion); + when(() => logger.progress(any())).thenReturn(_MockProgress()); + final result = await commandRunner.run(['update']); + expect(result, equals(ExitCode.success.code)); + verify( + () => logger.info('CLI is already at the latest version.'), + ).called(1); + verifyNever(() => logger.progress('Updating to $latestVersion')); + verifyNever( + () => pubUpdater.update( + packageName: any(named: 'packageName'), + versionConstraint: any(named: 'versionConstraint'), + ), + ); + }); }); } diff --git a/test/src/deps/dependency_resolver_test.dart b/test/src/deps/dependency_resolver_test.dart index e46bb2a..b856748 100644 --- a/test/src/deps/dependency_resolver_test.dart +++ b/test/src/deps/dependency_resolver_test.dart @@ -22,42 +22,40 @@ class _FakeProvisioner implements HostProvisioner { @override Future simulate(Set names) async => ProvisionPlan( - requested: names.toList(), - toInstall: names.difference(installed).toList(), - ); + requested: names.toList(), + toInstall: names.difference(installed).toList(), + ); @override Future install( Set names, { void Function(ProvisionProgress progress)? onProgress, - }) async => - ProvisionResult(installed: names.toList()); + }) async => ProvisionResult(installed: names.toList()); @override Future dispose() async {} } HostInfo _fedora() => const HostInfo( - os: HostOs.linux, - machineArch: 'x86_64', - archAliases: {'x86_64', 'x64', 'amd64'}, - hostType: 'fedora', - versionId: '43', - ); + os: HostOs.linux, + machineArch: 'x86_64', + archAliases: {'x86_64', 'x64', 'amd64'}, + hostType: 'fedora', + versionId: '43', +); EmbManifest _manifest( String id, Map deps, { List archs = const [], List hostTypes = const [], -}) => - EmbManifest.fromMap({ - 'id': id, - 'type': 'dependency', - if (archs.isNotEmpty) 'supported_archs': archs, - if (hostTypes.isNotEmpty) 'supported_host_types': hostTypes, - 'deps': deps, - }); +}) => EmbManifest.fromMap({ + 'id': id, + 'type': 'dependency', + if (archs.isNotEmpty) 'supported_archs': archs, + if (hostTypes.isNotEmpty) 'supported_host_types': hostTypes, + 'deps': deps, +}); void main() { final resolver = DependencyResolver(_fedora()); @@ -136,30 +134,31 @@ void main() { }, }), ]); - final filtered = - await resolver.filter(coalesced, _FakeProvisioner({'git'})); + final filtered = await resolver.filter( + coalesced, + _FakeProvisioner({'git'}), + ); expect(filtered.isSatisfied, isTrue); }); }); group('contentHash', () { List manifests() => [ - _manifest('a', { - 'linux': { - 'fedora': ['git', 'cmake'], - }, - }), - _manifest('b', { - 'linux': { - 'fedora': ['cmake', 'ninja-build'], - }, - }), - ]; + _manifest('a', { + 'linux': { + 'fedora': ['git', 'cmake'], + }, + }), + _manifest('b', { + 'linux': { + 'fedora': ['cmake', 'ninja-build'], + }, + }), + ]; test('is stable regardless of manifest order', () { final h1 = resolver.coalesce(manifests()).contentHash; - final h2 = - resolver.coalesce(manifests().reversed.toList()).contentHash; + final h2 = resolver.coalesce(manifests().reversed.toList()).contentHash; expect(h1, h2); }); @@ -188,22 +187,20 @@ void main() { ), ); // Same package set, different host identity → different cache key. - final ubuntuHash = ubuntu - .coalesce([ - _manifest('a', { - 'linux': { - 'fedora': ['git', 'cmake'], - 'ubuntu': ['git', 'cmake'], - }, - }), - _manifest('b', { - 'linux': { - 'fedora': ['cmake', 'ninja-build'], - 'ubuntu': ['cmake', 'ninja-build'], - }, - }), - ]) - .contentHash; + final ubuntuHash = ubuntu.coalesce([ + _manifest('a', { + 'linux': { + 'fedora': ['git', 'cmake'], + 'ubuntu': ['git', 'cmake'], + }, + }), + _manifest('b', { + 'linux': { + 'fedora': ['cmake', 'ninja-build'], + 'ubuntu': ['cmake', 'ninja-build'], + }, + }), + ]).contentHash; expect(fedoraHash, isNot(ubuntuHash)); }); }); diff --git a/test/src/flutter/flutter_sdk_test.dart b/test/src/flutter/flutter_sdk_test.dart index eb171d7..d514051 100644 --- a/test/src/flutter/flutter_sdk_test.dart +++ b/test/src/flutter/flutter_sdk_test.dart @@ -30,10 +30,13 @@ void main() { expect(result.path, p.join(tmp.path, 'flutter')); // Clone with the version as branch/tag into the `flutter` dir. - expect( - git.calls.first, - ['clone', FlutterSdk.repoUrl, 'flutter', '-b', '3.44.2'], - ); + expect(git.calls.first, [ + 'clone', + FlutterSdk.repoUrl, + 'flutter', + '-b', + '3.44.2', + ]); expect(git.calls, contains(equals(['checkout', '3.44.2']))); }); @@ -44,11 +47,13 @@ void main() { Directory(p.join(tmp.path, 'flutter', '.git')).createSync(recursive: true); final internal = Directory(p.join(tmp.path, 'flutter', 'bin', 'internal')) ..createSync(recursive: true); - File(p.join(internal.path, 'engine.version')) - .writeAsStringSync('deadbeefcafe\n'); + File( + p.join(internal.path, 'engine.version'), + ).writeAsStringSync('deadbeefcafe\n'); - final result = - await FlutterSdk(ws).install('3.44.2', runner: _FakeGit().run); + final result = await FlutterSdk( + ws, + ).install('3.44.2', runner: _FakeGit().run); expect(result.engineCommit, 'deadbeefcafe'); }); } diff --git a/test/src/host/host_info_test.dart b/test/src/host/host_info_test.dart index 12fb71c..61768f6 100644 --- a/test/src/host/host_info_test.dart +++ b/test/src/host/host_info_test.dart @@ -2,13 +2,13 @@ import 'package:emb_cli/src/host/host_info.dart'; import 'package:test/test.dart'; HostInfo _fedora({String arch = 'x86_64', Set? aliases}) => HostInfo( - os: HostOs.linux, - machineArch: arch, - archAliases: aliases ?? {'x86_64', 'amd64', 'x64'}, - hostType: 'fedora', - versionId: '43', - prettyName: 'Fedora Linux 43 (Workstation Edition)', - ); + os: HostOs.linux, + machineArch: arch, + archAliases: aliases ?? {'x86_64', 'amd64', 'x64'}, + hostType: 'fedora', + versionId: '43', + prettyName: 'Fedora Linux 43 (Workstation Edition)', +); void main() { group('parseOsRelease', () { diff --git a/test/src/manifest/host_deps_test.dart b/test/src/manifest/host_deps_test.dart index b13be31..5a8fa80 100644 --- a/test/src/manifest/host_deps_test.dart +++ b/test/src/manifest/host_deps_test.dart @@ -7,14 +7,13 @@ HostInfo _host({ String hostType = 'fedora', String versionId = '43', String arch = 'x86_64', -}) => - HostInfo( - os: os, - machineArch: arch, - archAliases: arch == 'x86_64' ? {'x86_64', 'x64', 'amd64'} : {arch}, - hostType: hostType, - versionId: versionId, - ); +}) => HostInfo( + os: os, + machineArch: arch, + archAliases: arch == 'x86_64' ? {'x86_64', 'x64', 'amd64'} : {arch}, + hostType: hostType, + versionId: versionId, +); void main() { group('extractPackageNames', () { @@ -28,7 +27,8 @@ void main() { test('extracts from apt-get with mixed flags', () { expect( extractPackageNames( - 'sudo apt-get install -yq graphviz libffi-dev ninja-build'), + 'sudo apt-get install -yq graphviz libffi-dev ninja-build', + ), ['graphviz', 'libffi-dev', 'ninja-build'], ); }); @@ -36,7 +36,8 @@ void main() { test('extracts from apt with long flags', () { expect( extractPackageNames( - 'sudo apt install --no-install-recommends -y git curl'), + 'sudo apt install --no-install-recommends -y git curl', + ), ['git', 'curl'], ); }); @@ -49,10 +50,10 @@ void main() { }); test('handles pacman -S', () { - expect( - extractPackageNames('sudo pacman -S wayland weston'), - ['wayland', 'weston'], - ); + expect(extractPackageNames('sudo pacman -S wayland weston'), [ + 'wayland', + 'weston', + ]); }); }); @@ -71,17 +72,16 @@ void main() { }); test('resolves macos flat list', () { - expect( - deps.resolve(_host(os: HostOs.macos, hostType: 'darwin')), - ['pkg-config', 'freetype'], - ); + expect(deps.resolve(_host(os: HostOs.macos, hostType: 'darwin')), [ + 'pkg-config', + 'freetype', + ]); }); test('resolves windows list', () { - expect( - deps.resolve(_host(os: HostOs.windows, hostType: 'windows')), - ['Kitware.CMake'], - ); + expect(deps.resolve(_host(os: HostOs.windows, hostType: 'windows')), [ + 'Kitware.CMake', + ]); }); }); diff --git a/test/src/manifest/manifest_loader_test.dart b/test/src/manifest/manifest_loader_test.dart index fef4199..04c47f8 100644 --- a/test/src/manifest/manifest_loader_test.dart +++ b/test/src/manifest/manifest_loader_test.dart @@ -60,10 +60,11 @@ deps: expect(m.deps.resolve(fedora), ['pkg-config', 'freetype-devel']); }); - test('loads an emb: key from pubspec.yaml, defaulting id to package name', - () { - final pkg = Directory(p.join(tmp.path, 'pkgb'))..createSync(); - File(p.join(pkg.path, 'pubspec.yaml')).writeAsStringSync(''' + test( + 'loads an emb: key from pubspec.yaml, defaulting id to package name', + () { + final pkg = Directory(p.join(tmp.path, 'pkgb'))..createSync(); + File(p.join(pkg.path, 'pubspec.yaml')).writeAsStringSync(''' name: pkgb environment: sdk: ^3.4.0 @@ -73,11 +74,12 @@ emb: linux: fedora: [cmake] '''); - final m = loader.loadPackageDir(pkg); - expect(m, isNotNull); - expect(m!.id, 'pkgb'); - expect(m.deps.resolve(fedora), ['cmake']); - }); + final m = loader.loadPackageDir(pkg); + expect(m, isNotNull); + expect(m!.id, 'pkgb'); + expect(m.deps.resolve(fedora), ['cmake']); + }, + ); test('discoverPackages finds manifests in subdirectories', () { final a = Directory(p.join(tmp.path, 'a'))..createSync(); diff --git a/test/src/repo/git_repo_test.dart b/test/src/repo/git_repo_test.dart index 48796db..7890305 100644 --- a/test/src/repo/git_repo_test.dart +++ b/test/src/repo/git_repo_test.dart @@ -24,8 +24,9 @@ void main() { group('folderName', () { test('strips trailing .git from the uri basename', () { expect( - const GitRepo(uri: 'https://github.com/flutter/super_dash.git') - .folderName, + const GitRepo( + uri: 'https://github.com/flutter/super_dash.git', + ).folderName, 'super_dash', ); }); @@ -60,8 +61,13 @@ void main() { final result = await repo.sync(tmp, runner: git.run); expect(result.success, isTrue); - expect(git.calls.first, - ['clone', 'https://x/y/foo.git', 'foo', '-b', 'main']); + expect(git.calls.first, [ + 'clone', + 'https://x/y/foo.git', + 'foo', + '-b', + 'main', + ]); expect(git.calls, contains(equals(['checkout', 'main']))); }); @@ -93,8 +99,11 @@ void main() { test('checks out an explicit rev over the branch', () async { final git = _FakeGit(); - const repo = - GitRepo(uri: 'https://x/y/foo.git', branch: 'main', rev: 'abc123'); + const repo = GitRepo( + uri: 'https://x/y/foo.git', + branch: 'main', + rev: 'abc123', + ); await repo.sync(tmp, runner: git.run); expect(git.calls, contains(equals(['checkout', 'abc123']))); expect(git.calls, isNot(contains(equals(['checkout', 'main']))));