fix: relative to the current directory rules (#3297)
* test for nested exact dir ignore rules
(cherry picked from commit 10aecef0c0678c84fbf7930294d6778d87568cbf)
* fix nested "only in current directory" statements
(starting with `/` symbol)
(cherry picked from commit ad3d5ac10ed5d1601f767e8db25e2fe5d39f88b2)
* add tests for delimeter in the middle
* do not append delimiter for single delimeter path
* dart fmt
diff --git a/lib/src/ignore.dart b/lib/src/ignore.dart
index ff22dff..34e51fb 100644
--- a/lib/src/ignore.dart
+++ b/lib/src/ignore.dart
@@ -25,7 +25,6 @@
/// [Ignore.listFiles].
///
/// [1]: https://git-scm.com/docs/gitignore
-
import 'package:meta/meta.dart';
/// A set of ignore rules representing a single ignore file.
@@ -148,7 +147,8 @@
path.endsWith('/') ? path.substring(0, path.length - 1) : path;
return listFiles(
beneath: pathWithoutSlash,
- includeDirs: true, // because we are listing below pathWithoutSlash
+ includeDirs: true,
+ // because we are listing below pathWithoutSlash
listDir: (dir) {
// List the next part of path:
if (dir == pathWithoutSlash) return [];
@@ -285,8 +285,10 @@
}
if (currentIsDir) {
final ignore = ignoreForDir(normalizedCurrent);
- ignoreStack
- .add(ignore == null ? null : _IgnorePrefixPair(ignore, current));
+ ignoreStack.add(ignore == null
+ ? null
+ : _IgnorePrefixPair(
+ ignore, current == '/' ? current : '$current/'));
// Put all entities in current on the stack to be processed.
toVisit.add(listDir(normalizedCurrent).map((x) => '/$x').toList());
if (includeDirs) {
@@ -309,13 +311,16 @@
// An invalid pattern is also considered empty.
bool get empty => rule == null;
+
bool get valid => exception == null;
// For invalid patterns this contains a description of the problem.
final FormatException? exception;
_IgnoreParseResult(this.pattern, this.rule) : exception = null;
+
_IgnoreParseResult.invalid(this.pattern, this.exception) : rule = null;
+
_IgnoreParseResult.empty(this.pattern)
: rule = null,
exception = null;
@@ -540,7 +545,9 @@
class _IgnorePrefixPair {
final Ignore ignore;
final String prefix;
+
_IgnorePrefixPair(this.ignore, this.prefix);
+
@override
String toString() {
return '{${ignore._rules.map((r) => r.original)} $prefix}';
diff --git a/test/package_list_files_test.dart b/test/package_list_files_test.dart
index 091001b..013f3a1 100644
--- a/test/package_list_files_test.dart
+++ b/test/package_list_files_test.dart
@@ -423,6 +423,170 @@
p.join(root, 'pubignoredir', 'b.txt'),
});
});
+
+ group('relative to current directory rules', () {
+ setUp(ensureGit);
+ group('delimiter in the beginning', () {
+ test('ignore directory in exact directory', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.dir('nested', [
+ d.file('.gitignore', '/bin/'),
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ });
+ });
+
+ test('ignore directory in exact directory', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.dir('nested', [
+ d.file('.gitignore', '/bin/'),
+ d.appPubspec(),
+ d.file('bin'),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ p.join(root, 'bin'),
+ });
+ });
+
+ test('ignore file on exact directory', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.dir('nested', [
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('.gitignore', '/run.dart'),
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ });
+ });
+
+ test('not ignore files beneath exact directory', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.dir('nested', [
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('.gitignore', '/run.dart'),
+ d.file('run.dart'),
+ d.dir('nested_again', [
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ p.join(root, 'bin', 'nested_again', 'run.dart'),
+ });
+ });
+
+ test('disable ignore in exact directory', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.file('.gitignore', 'run.dart'),
+ d.dir('nested', [
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('.gitignore', '!/run.dart'),
+ d.file('run.dart'),
+ d.dir('nested_again', [
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ p.join(root, 'bin', 'run.dart'),
+ });
+ });
+ });
+ });
+
+ group('delimiter in the middle', () {
+ test('should work with route relative to current directory ', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.file('.gitignore', 'nested/bin/run.dart'),
+ d.dir('nested', [
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('run.dart'),
+ d.dir('nested_again', [
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ p.join(root, 'bin', 'nested_again', 'run.dart'),
+ });
+ });
+
+ test('should not have effect in nested folders', () async {
+ final repo = d.git(appPath, [
+ d.dir('packages', [
+ d.file('.gitignore', 'bin/run.dart'),
+ d.dir('nested', [
+ d.appPubspec(),
+ d.dir('bin', [
+ d.file('run.dart'),
+ d.dir('nested_again', [
+ d.file('run.dart'),
+ ]),
+ ]),
+ ]),
+ ]),
+ ]);
+ await repo.create();
+ createEntrypoint(p.join(appPath, 'packages', 'nested'));
+
+ expect(entrypoint!.root.listFiles(), {
+ p.join(root, 'pubspec.yaml'),
+ p.join(root, 'bin', 'run.dart'),
+ p.join(root, 'bin', 'nested_again', 'run.dart'),
+ });
+ });
+ });
}
void createEntrypoint([String? path]) {