diff --git a/lib/src/cli/cli.dart b/lib/src/cli/cli.dart index 49ec55b0..da35b7dd 100644 --- a/lib/src/cli/cli.dart +++ b/lib/src/cli/cli.dart @@ -162,8 +162,22 @@ const _ignoredDirectories = { }; bool _isPubspec(FileSystemEntity entity) { - final segments = p.split(entity.path).toSet(); - if (segments.intersection(_ignoredDirectories).isNotEmpty) return false; if (entity is! File) return false; return p.basename(entity.path) == 'pubspec.yaml'; } + +extension on Set { + bool excludes(FileSystemEntity entity) { + final segments = p.split(entity.path).toSet(); + if (segments.intersection(_ignoredDirectories).isNotEmpty) return true; + if (segments.intersection(this).isNotEmpty) return true; + + for (final value in this) { + if (Glob(value).matches(entity.path)) { + return true; + } + } + + return false; + } +} diff --git a/lib/src/cli/dart_cli.dart b/lib/src/cli/dart_cli.dart index 89796437..e79f65d4 100644 --- a/lib/src/cli/dart_cli.dart +++ b/lib/src/cli/dart_cli.dart @@ -19,6 +19,7 @@ class Dart { required Logger logger, String cwd = '.', bool recursive = false, + Set ignore = const {}, }) async { if (!recursive) { final pubspec = File(p.join(cwd, 'pubspec.yaml')); @@ -40,7 +41,7 @@ class Dart { workingDirectory: entity.parent.path, logger: logger, ), - where: _isPubspec, + where: (entity) => !ignore.excludes(entity) && _isPubspec(entity), cwd: cwd, ); diff --git a/lib/src/cli/flutter_cli.dart b/lib/src/cli/flutter_cli.dart index 2097c240..c4c0667f 100644 --- a/lib/src/cli/flutter_cli.dart +++ b/lib/src/cli/flutter_cli.dart @@ -80,6 +80,7 @@ class Flutter { required Logger logger, String cwd = '.', bool recursive = false, + Set ignore = const {}, }) async { await _runCommand( cmd: (cwd) async { @@ -107,6 +108,7 @@ class Flutter { }, cwd: cwd, recursive: recursive, + ignore: ignore, ); } @@ -115,6 +117,7 @@ class Flutter { required Logger logger, String cwd = '.', bool recursive = false, + Set ignore = const {}, }) async { await _runCommand( cmd: (cwd) => _Cmd.run( @@ -125,6 +128,7 @@ class Flutter { ), cwd: cwd, recursive: recursive, + ignore: ignore, ); } @@ -136,6 +140,7 @@ class Flutter { bool recursive = false, bool collectCoverage = false, bool optimizePerformance = false, + Set ignore = const {}, double? minCoverage, String? excludeFromCoverage, String? randomSeed, @@ -237,6 +242,7 @@ class Flutter { }, cwd: cwd, recursive: recursive, + ignore: ignore, ); } @@ -287,6 +293,7 @@ Future> _runCommand({ required Future Function(String cwd) cmd, required String cwd, required bool recursive, + required Set ignore, }) async { if (!recursive) { final pubspec = File(p.join(cwd, 'pubspec.yaml')); @@ -297,7 +304,7 @@ Future> _runCommand({ final processes = _Cmd.runWhere( run: (entity) => cmd(entity.parent.path), - where: _isPubspec, + where: (entity) => !ignore.excludes(entity) && _isPubspec(entity), cwd: cwd, ); diff --git a/lib/src/commands/packages.dart b/lib/src/commands/packages.dart index db6c46d2..ffe43bcc 100644 --- a/lib/src/commands/packages.dart +++ b/lib/src/commands/packages.dart @@ -28,12 +28,17 @@ class PackagesCommand extends Command { class PackagesGetCommand extends Command { /// {@macro packages_get_command} PackagesGetCommand({Logger? logger}) : _logger = logger ?? Logger() { - argParser.addFlag( - 'recursive', - abbr: 'r', - help: 'Install dependencies recursively for all nested packages.', - negatable: false, - ); + argParser + ..addFlag( + 'recursive', + abbr: 'r', + help: 'Install dependencies recursively for all nested packages.', + negatable: false, + ) + ..addMultiOption( + 'ignore', + help: 'Exclude packages from installing dependencies.', + ); } final Logger _logger; @@ -57,6 +62,7 @@ class PackagesGetCommand extends Command { } final recursive = _argResults['recursive'] as bool; + final ignore = (_argResults['ignore'] as List).toSet(); final target = _argResults.rest.length == 1 ? _argResults.rest[0] : '.'; final targetPath = path.normalize(Directory(target).absolute.path); final isFlutterInstalled = await Flutter.installed(logger: _logger); @@ -65,6 +71,7 @@ class PackagesGetCommand extends Command { await Flutter.packagesGet( cwd: targetPath, recursive: recursive, + ignore: ignore, logger: _logger, ); } on PubspecNotFound catch (_) { diff --git a/test/src/cli/flutter_cli_test.dart b/test/src/cli/flutter_cli_test.dart index 4b13a2aa..7eb2c21c 100644 --- a/test/src/cli/flutter_cli_test.dart +++ b/test/src/cli/flutter_cli_test.dart @@ -168,25 +168,61 @@ void main() { ); }); - test('completes when there is a pubspec.yaml (recursive)', () { - final directory = Directory.systemTemp.createTempSync(); - final nestedDirectory = Directory(p.join(directory.path, 'test')) - ..createSync(); - File(p.join(nestedDirectory.path, 'pubspec.yaml')) - .writeAsStringSync(_pubspec); - - ProcessOverrides.runZoned( - () => expectLater( - Flutter.packagesGet( - cwd: directory.path, - recursive: true, - logger: logger, + test( + 'completes when there is a pubspec.yaml and ' + 'directory is ignored (recursive)', + () { + final directory = Directory.systemTemp.createTempSync(); + final nestedDirectory = Directory(p.join(directory.path, 'test')) + ..createSync(); + final ignoredDirectory = Directory( + p.join(directory.path, 'test_plugin'), + )..createSync(); + + File(p.join(nestedDirectory.path, 'pubspec.yaml')) + .writeAsStringSync(_pubspec); + File(p.join(ignoredDirectory.path, 'pubspec.yaml')) + .writeAsStringSync(_pubspec); + + ProcessOverrides.runZoned( + () => expectLater( + Flutter.packagesGet( + cwd: directory.path, + recursive: true, + ignore: { + 'test_plugin', + '/**/test_plugin_two/**', + }, + logger: logger, + ), + completes, ), - completes, - ), - runProcess: process.run, - ); - }); + runProcess: process.run, + ).whenComplete(() { + verify(() { + logger.progress( + any( + that: contains( + 'Running "flutter packages get" in ' + '${nestedDirectory.path}', + ), + ), + ); + }).called(1); + + verifyNever(() { + logger.progress( + any( + that: contains( + 'Running "flutter packages get" in ' + '${ignoredDirectory.path}', + ), + ), + ); + }); + }); + }, + ); }); group('.pubGet', () { diff --git a/test/src/commands/packages_test.dart b/test/src/commands/packages_test.dart index 9db74c14..08d66b19 100644 --- a/test/src/commands/packages_test.dart +++ b/test/src/commands/packages_test.dart @@ -34,6 +34,7 @@ const expectedPackagesGetUsage = [ 'Usage: very_good packages get [arguments]\n' '-h, --help Print this usage information.\n' '''-r, --recursive Install dependencies recursively for all nested packages.\n''' + ' --ignore Exclude packages from installing dependencies.\n' '\n' 'Run "very_good help" to see global options.' ]; @@ -265,6 +266,77 @@ void main() { }).called(2); }), ); + + test( + 'completes normally ' + 'when pubspec.yaml exists and directory is ignored (recursive)', + withRunner((commandRunner, logger, pubUpdater, printLogs) async { + final tempDirectory = Directory.systemTemp.createTempSync(); + final directoryA = Directory( + path.join(tempDirectory.path, 'plugin_a'), + ); + final directoryB = Directory( + path.join(tempDirectory.path, 'plugin_b'), + ); + final pubspecA = File( + path.join(directoryA.path, 'example_a', 'pubspec.yaml'), + ); + final pubspecB = File( + path.join(directoryB.path, 'example_b', 'pubspec.yaml'), + ); + pubspecA + ..createSync(recursive: true) + ..writeAsStringSync( + ''' + name: example_a + version: 0.1.0 + + environment: + sdk: ">=2.12.0 <3.0.0" + ''', + ); + pubspecB + ..createSync(recursive: true) + ..writeAsStringSync( + ''' + name: example_b + version: 0.1.0 + + environment: + sdk: ">=2.12.0 <3.0.0" + ''', + ); + + final result = await commandRunner.run( + [ + 'packages', + 'get', + '--recursive', + '--ignore=plugin_b', + tempDirectory.path, + ], + ); + expect(result, equals(ExitCode.success.code)); + verify(() { + logger.progress( + any( + that: contains( + 'Running "flutter packages get" in ${directoryA.path}', + ), + ), + ); + }).called(1); + verifyNever(() { + logger.progress( + any( + that: contains( + 'Running "flutter packages get" in ${directoryB.path}', + ), + ), + ); + }); + }), + ); }); }); }