diff --git a/packages/shorebird_cli/lib/src/cache.dart b/packages/shorebird_cli/lib/src/cache.dart index 08c24a28..e5b24673 100644 --- a/packages/shorebird_cli/lib/src/cache.dart +++ b/packages/shorebird_cli/lib/src/cache.dart @@ -52,20 +52,31 @@ class Cache { } /// The Shorebird cache directory. - static Directory get shorebirdCacheDirectory => Directory( - p.join(ShorebirdEnvironment.shorebirdRoot.path, 'bin', 'cache'), - ); + static Directory get shorebirdCacheDirectory { + return Directory( + p.join(ShorebirdEnvironment.shorebirdRoot.path, 'bin', 'cache'), + ); + } /// The Shorebird cached artifacts directory. - static Directory get shorebirdArtifactsDirectory => Directory( - p.join(shorebirdCacheDirectory.path, 'artifacts'), - ); + static Directory get shorebirdArtifactsDirectory { + return Directory( + p.join(shorebirdCacheDirectory.path, 'artifacts'), + ); + } final List _artifacts = []; String get storageBaseUrl => 'https://storage.googleapis.com'; String get storageBucket => 'download.shorebird.dev'; + + void clear() { + final cacheDir = shorebirdCacheDirectory; + if (cacheDir.existsSync()) { + cacheDir.deleteSync(recursive: true); + } + } } abstract class CachedArtifact { diff --git a/packages/shorebird_cli/lib/src/command_runner.dart b/packages/shorebird_cli/lib/src/command_runner.dart index 0fdc0aa7..5fb72aed 100644 --- a/packages/shorebird_cli/lib/src/command_runner.dart +++ b/packages/shorebird_cli/lib/src/command_runner.dart @@ -38,6 +38,7 @@ class ShorebirdCliCommandRunner extends CompletionCommandRunner { addCommand(AccountCommand(logger: _logger)); addCommand(AppsCommand(logger: _logger)); addCommand(BuildCommand(logger: _logger)); + addCommand(CacheCommand(logger: _logger)); addCommand(ChannelsCommand(logger: _logger)); addCommand(DoctorCommand(logger: _logger)); addCommand(InitCommand(logger: _logger)); diff --git a/packages/shorebird_cli/lib/src/commands/cache/cache.dart b/packages/shorebird_cli/lib/src/commands/cache/cache.dart new file mode 100644 index 00000000..9b2afe4a --- /dev/null +++ b/packages/shorebird_cli/lib/src/commands/cache/cache.dart @@ -0,0 +1,2 @@ +export 'cache_command.dart'; +export 'clean_cache_command.dart'; diff --git a/packages/shorebird_cli/lib/src/commands/cache/cache_command.dart b/packages/shorebird_cli/lib/src/commands/cache/cache_command.dart new file mode 100644 index 00000000..10ce504d --- /dev/null +++ b/packages/shorebird_cli/lib/src/commands/cache/cache_command.dart @@ -0,0 +1,19 @@ +import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/commands/commands.dart'; + +/// {@template cache_command} +/// `shorebird cache` +/// Manage the Shorebird cache. +/// {@endtemplate} +class CacheCommand extends ShorebirdCommand { + /// {@macro cache_command} + CacheCommand({required super.logger, super.cache}) { + addSubcommand(CleanCacheCommand(logger: logger, cache: cache)); + } + + @override + String get description => 'Manage the Shorebird cache.'; + + @override + String get name => 'cache'; +} diff --git a/packages/shorebird_cli/lib/src/commands/cache/clean_cache_command.dart b/packages/shorebird_cli/lib/src/commands/cache/clean_cache_command.dart new file mode 100644 index 00000000..0f12b426 --- /dev/null +++ b/packages/shorebird_cli/lib/src/commands/cache/clean_cache_command.dart @@ -0,0 +1,30 @@ +import 'dart:async'; + +import 'package:mason_logger/mason_logger.dart'; +import 'package:shorebird_cli/src/command.dart'; +import 'package:shorebird_cli/src/shorebird_config_mixin.dart'; + +/// {@template clean_cache_command} +/// `shorebird cache clean` +/// Clears the Shorebird cache directory. +/// {@endtemplate} +class CleanCacheCommand extends ShorebirdCommand with ShorebirdConfigMixin { + /// {@macro clean_cache_command} + CleanCacheCommand({required super.logger, required super.cache}); + + @override + String get description => 'Clears the Shorebird cache directory.'; + + @override + String get name => 'clean'; + + @override + List get aliases => ['clear']; + + @override + Future run() async { + cache.clear(); + logger.success('✅ Cleared Cache!'); + return ExitCode.success.code; + } +} diff --git a/packages/shorebird_cli/lib/src/commands/commands.dart b/packages/shorebird_cli/lib/src/commands/commands.dart index cea59296..ce7f0325 100644 --- a/packages/shorebird_cli/lib/src/commands/commands.dart +++ b/packages/shorebird_cli/lib/src/commands/commands.dart @@ -1,6 +1,7 @@ export 'account_command.dart'; export 'apps/apps.dart'; export 'build_command.dart'; +export 'cache/cache.dart'; export 'channels/channels.dart'; export 'doctor_command.dart'; export 'init_command.dart'; diff --git a/packages/shorebird_cli/test/src/cache_test.dart b/packages/shorebird_cli/test/src/cache_test.dart index 394a08a6..3ad38215 100644 --- a/packages/shorebird_cli/test/src/cache_test.dart +++ b/packages/shorebird_cli/test/src/cache_test.dart @@ -84,6 +84,21 @@ void main() { }); }); + group('clear', () { + test('deletes the cache directory', () async { + Cache.shorebirdCacheDirectory.createSync(recursive: true); + expect(Cache.shorebirdCacheDirectory.existsSync(), isTrue); + cache.clear(); + expect(Cache.shorebirdCacheDirectory.existsSync(), isFalse); + }); + + test('does nothing if directory does not exist', () { + expect(Cache.shorebirdCacheDirectory.existsSync(), isFalse); + cache.clear(); + expect(Cache.shorebirdCacheDirectory.existsSync(), isFalse); + }); + }); + group('updateAll', () { group('patch', () { test('downloads correct artifacts', () async { diff --git a/packages/shorebird_cli/test/src/commands/cache/cache_command_test.dart b/packages/shorebird_cli/test/src/commands/cache/cache_command_test.dart new file mode 100644 index 00000000..077df1f5 --- /dev/null +++ b/packages/shorebird_cli/test/src/commands/cache/cache_command_test.dart @@ -0,0 +1,22 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:shorebird_cli/src/commands/cache/cache_command.dart'; +import 'package:test/test.dart'; + +class _MockLogger extends Mock implements Logger {} + +void main() { + group('cache', () { + late Logger logger; + late CacheCommand command; + + setUp(() { + logger = _MockLogger(); + command = CacheCommand(logger: logger); + }); + + test('has a description', () { + expect(command.description, isNotEmpty); + }); + }); +} diff --git a/packages/shorebird_cli/test/src/commands/cache/clean_cache_command_test.dart b/packages/shorebird_cli/test/src/commands/cache/clean_cache_command_test.dart new file mode 100644 index 00000000..778a380a --- /dev/null +++ b/packages/shorebird_cli/test/src/commands/cache/clean_cache_command_test.dart @@ -0,0 +1,34 @@ +import 'package:mason_logger/mason_logger.dart'; +import 'package:mocktail/mocktail.dart'; +import 'package:shorebird_cli/src/cache.dart'; +import 'package:shorebird_cli/src/commands/commands.dart'; +import 'package:test/test.dart'; + +class _MockLogger extends Mock implements Logger {} + +class _MockCache extends Mock implements Cache {} + +void main() { + group('cache clean', () { + late Cache cache; + late Logger logger; + late CleanCacheCommand command; + + setUp(() { + cache = _MockCache(); + logger = _MockLogger(); + command = CleanCacheCommand(cache: cache, logger: logger); + }); + + test('has a description', () { + expect(command.description, isNotEmpty); + }); + + test('clears the cache', () async { + final result = await command.run(); + expect(result, equals(ExitCode.success.code)); + verify(() => logger.success('✅ Cleared Cache!')).called(1); + verify(cache.clear).called(1); + }); + }); +}