Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(mason): define BrickIgnore class #1227

Closed
90 changes: 90 additions & 0 deletions packages/mason/lib/src/brick_ignore.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import 'dart:collection';
import 'dart:io';

import 'package:glob/glob.dart';
import 'package:mason/mason.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart' as path;

/// A file that defines what brick files or directories should be ignored during
/// bundling.
///
/// Only those directories and files under `__brick__` can be ignored.
///
/// For example, given the following brick directory:
///
/// ```txt
/// __brick__/
/// ├─ HELLO.md
/// └─ goodbye.dart
/// brick.yaml
/// .brickignore
/// README.md
/// ```
///
/// And the following `.brickignore` file content:
///
/// ```txt
/// **.md
/// ```
///
/// The `HELLO.md` file will be ignored during bundling, but `goodbye.dart` will
/// not be ignored. Those other files not under `__brick__` are not bundled,
/// hence they can not be ignored.
///
/// See also:
///
/// * [createBundle], which creates a [MasonBundle] from a brick directory.
@internal
class BrickIgnore {
BrickIgnore._({
required Iterable<Glob> globs,
required String path,
required String brickDirectoryPath,
}) : _globs = UnmodifiableListView(globs),
_path = path,
_brickDirectoryPath = brickDirectoryPath;

/// Creates a [BrickIgnore] from a [File].
factory BrickIgnore.fromFile(File file) {
final lines = file.readAsLinesSync();
final globs = lines.map(Glob.new);

final brickDirectoryPath = path.join(file.parent.path, BrickYaml.dir);

return BrickIgnore._(
globs: globs,
path: file.path,
brickDirectoryPath: brickDirectoryPath,
);
}

/// The name of the file to be used as the ignore file.
static const file = '.brickignore';

final UnmodifiableListView<Glob> _globs;

/// The absolute path to the ignore file.
final String _path;

/// The absolute path to the directory where all brick templated files are
/// located.
///
/// See also:
///
/// * [BrickYaml.dir], which is the name of the directory where the templated
/// brick files are located.
final String _brickDirectoryPath;

/// Whether or not the [filePath] is ignored.
///
/// Immediately returns false if the [filePath] is not within the brick
/// directory (`__brick__`). Otherwise, checks if the [filePath] matches
/// any of the globs in the ignore file.
bool isIgnored(String filePath) {
if (!path.isWithin(_brickDirectoryPath, filePath)) return false;

final relativePath = path.relative(filePath, from: path.dirname(_path));
return _globs.any((glob) => glob.matches(relativePath));
}
}
1 change: 1 addition & 0 deletions packages/mason/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ dependencies:
collection: ^1.15.0
convert: ^3.1.0
crypto: ^3.0.1
glob: ^2.1.2
http: '>=0.13.3 <2.0.0'
json_annotation: ^4.8.1
mason_logger: ^0.2.11
Expand Down
80 changes: 80 additions & 0 deletions packages/mason/test/src/brick_ignore_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import 'dart:io';

import 'package:mason/src/brick_ignore.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

void main() {
group('$BrickIgnore', () {
late File brickIgnoreFile;

setUp(() {
final temporaryDirectory = Directory.systemTemp.createTempSync();
addTearDown(() => temporaryDirectory.deleteSync(recursive: true));

brickIgnoreFile =
File(path.join(temporaryDirectory.path, BrickIgnore.file))
..createSync();
});

test('fromFile returns normally', () {
expect(
() => BrickIgnore.fromFile(brickIgnoreFile),
returnsNormally,
);
});

group('isIgnored', () {
test('returns true when the file is ignored', () {
brickIgnoreFile.writeAsStringSync('**.md');
final brickIgnore = BrickIgnore.fromFile(brickIgnoreFile);

final ignoredFilePath = path.join(
brickIgnoreFile.parent.path,
'__brick__',
'HELLO.md',
);

expect(
brickIgnore.isIgnored(ignoredFilePath),
isTrue,
reason: '`HELLO.md` is under `__brick__` and is ignored by `**.md`',
);
});

test(
'returns false when the file to be ignored is not under __brick__',
() {
brickIgnoreFile.writeAsStringSync('**.md');
final brickIgnore = BrickIgnore.fromFile(brickIgnoreFile);

final ignoredFilePath =
path.join(brickIgnoreFile.parent.path, 'HELLO.md');

expect(
brickIgnore.isIgnored(ignoredFilePath),
isFalse,
reason: '`HELLO.md` is not under `__brick__`',
);
},
);

test('returns false when the file is not ignored', () {
brickIgnoreFile.writeAsStringSync('');
final brickIgnore = BrickIgnore.fromFile(brickIgnoreFile);

final ignoredFilePath = path.join(
brickIgnoreFile.parent.path,
'__brick__',
'HELLO.md',
);

expect(
brickIgnore.isIgnored(ignoredFilePath),
isFalse,
reason: '`HELLO.md` is under `__brick__` and there are no ignores',
);
});
});
});
}
Loading