Repository navigation
Conversation
Package publishingIf you have publishing permissions, you can use the links below to publish the changes after merging this PR.
Documentation at https://github.com/dart-lang/ecosystem/wiki/Publishing-automation. |
PR HealthUnused Dependencies ✔️
For details on how to fix these, see dependency_validator. This check can be disabled by tagging the PR with Breaking changes ✔️
This check can be disabled by tagging the PR with API leaks ✔️The following packages contain symbols visible in the public API, but not exported by the library. Export these symbols or remove them from your publicly visible API.
This check can be disabled by tagging the PR with Changelog Entry ✔️
Changes to files need to be accounted for in their respective changelogs. This check can be disabled by tagging the PR with License Headers ✔️
All source files should start with a license header. Unrelated files missing license headers
This check can be disabled by tagging the PR with
Coverage
|
| File | Coverage |
|---|---|
| pkgs/glob/lib/glob.dart | 💚 98 % ⬆️ 0 % |
| pkgs/glob/lib/src/list_tree.dart | 💔 95 % ⬇️ 1 % |
This check for test coverage is informational (issues shown here will not fail the PR).
This check can be disabled by tagging the PR with skip-coverage-check.
There was a problem hiding this comment.
Code Review
This pull request updates the glob package to use the file system's path context instead of the platform's path context when listing files. The review feedback identifies a critical bug where text.replaceAll is called as a no-op on an immutable string, and p.isAbsolute is incorrectly used instead of fileSystem.path.isAbsolute. Additionally, the reviewer points out that the new tests are false positives because they do not fully consume the stream or populate the mock file system, and suggests cleaner string formatting for error messages to improve readability.
| if (fileSystem.path.style == p.windows.style) | ||
| text.replaceAll('/', r'\'); | ||
| if (p.isAbsolute(text)) { |
There was a problem hiding this comment.
The call to text.replaceAll is a no-op because strings in Dart are immutable. The returned string is discarded, leaving text unchanged. It must be assigned back to text.
Additionally, p.isAbsolute(text) on line 94 uses the platform-specific path context p instead of the file system's path context fileSystem.path.isAbsolute(text). When the file system style differs from the platform style (e.g., Windows style on a Posix platform), this check will return incorrect results.
| if (fileSystem.path.style == p.windows.style) | |
| text.replaceAll('/', r'\'); | |
| if (p.isAbsolute(text)) { | |
| if (fileSystem.path.style == p.windows.style) { | |
| text = text.replaceAll('/', r'\'); | |
| } | |
| if (fileSystem.path.isAbsolute(text)) { |
References
- In Dart, a raw string literal can end with a backslash (e.g., r'') without causing an unterminated string literal error. The backslash is treated as a literal character, not an escape for the closing quote.
| test("does not fail if the fileSystem and glob contexts match", () { | ||
| // Shouldn't fail even if neither is the platform context. | ||
| Glob('*', context: p.posix) | ||
| .listFileSystem(MemoryFileSystem(style: FileSystemStyle.posix)); | ||
| Glob('*', context: p.windows) | ||
| .listFileSystem(MemoryFileSystem(style: FileSystemStyle.windows)); | ||
| }); |
There was a problem hiding this comment.
This test passes, but it is currently a false positive. Because listFileSystem returns a lazy Stream, and the test never listens to or awaits the stream (e.g., by calling .toList()), the actual path listing code is never executed.
If you listen to the stream, the test will fail on platforms with a different path style because _ListTreeNode.list still uses the platform-specific p context (like p.relative, p.join) instead of fileSystem.path.
To make this test robust and catch actual runtime failures, you should populate the memory file system with a file and fully consume the stream using await ...toList().
test("does not fail if the fileSystem and glob contexts match", () async {
// Shouldn't fail even if neither is the platform context.
var posixFs = MemoryFileSystem(style: FileSystemStyle.posix);
posixFs.file('/foo').createSync(recursive: true);
await Glob('/*', context: p.posix)
.listFileSystem(posixFs)
.toList();
var windowsFs = MemoryFileSystem(style: FileSystemStyle.windows);
windowsFs.file('C:\\foo').createSync(recursive: true);
await Glob('C:\\*', context: p.windows)
.listFileSystem(windowsFs)
.toList();
});| test("does not fail if the fileSystem and glob contexts match", () { | ||
| // Shouldn't fail even if neither is the platform context. | ||
| Glob('*', context: p.posix) | ||
| .listFileSystemSync(MemoryFileSystem(style: FileSystemStyle.posix)); | ||
| Glob('*', context: p.windows) | ||
| .listFileSystemSync(MemoryFileSystem(style: FileSystemStyle.windows)); | ||
| }); |
There was a problem hiding this comment.
Similar to the async test, this synchronous test passes only because the MemoryFileSystem is completely empty. When the file system is empty, listSync returns early without executing the path manipulation code (which still incorrectly uses the platform-specific p context).
To ensure this test is actually validating cross-platform compatibility, populate the file system with a file so that the path traversal and matching logic are executed.
test("does not fail if the fileSystem and glob contexts match", () {
// Shouldn't fail even if neither is the platform context.
var posixFs = MemoryFileSystem(style: FileSystemStyle.posix);
posixFs.file('/foo').createSync(recursive: true);
Glob('/*', context: p.posix).listFileSystemSync(posixFs);
var windowsFs = MemoryFileSystem(style: FileSystemStyle.windows);
windowsFs.file('C:\\foo').createSync(recursive: true);
Glob('C:\\*', context: p.windows).listFileSystemSync(windowsFs);
});| throw ArgumentError.value( | ||
| fileSystem, | ||
| 'fileSystem', | ||
| '''Can't list using glob \"$this\"; it matches ''' | ||
| '${context.style} paths, but the file system uses ' | ||
| '${fileSystem.path.style} paths.'); |
There was a problem hiding this comment.
The string literal concatenation here uses an inconsistent mix of triple-quotes ''' and single quotes ', and unnecessarily escapes the double quotes \" inside the triple-quotes.
To adhere to the repository style guide's philosophy of "Optimize for readability", we should use a consistent and cleaner string quoting style. Since the string contains single quotes (Can't), we can use double quotes for the first segment and single quotes for the rest, avoiding any triple-quotes or unnecessary escaping.
| throw ArgumentError.value( | |
| fileSystem, | |
| 'fileSystem', | |
| '''Can't list using glob \"$this\"; it matches ''' | |
| '${context.style} paths, but the file system uses ' | |
| '${fileSystem.path.style} paths.'); | |
| throw ArgumentError.value( | |
| fileSystem, | |
| 'fileSystem', | |
| "Can't list using glob \"$this\"; it matches " | |
| '${context.style} paths, but the file system uses ' | |
| '${fileSystem.path.style} paths.'); |
References
- Optimize for readability - code is read more often than it is written. (link)
| throw ArgumentError.value( | ||
| fileSystem, | ||
| 'fileSystem', | ||
| '''Can't list using glob \"$this\"; it matches ''' | ||
| '${context.style} paths, but the file system uses ' | ||
| '${fileSystem.path.style} paths.'); |
There was a problem hiding this comment.
The string literal concatenation here uses an inconsistent mix of triple-quotes ''' and single quotes ', and unnecessarily escapes the double quotes \" inside the triple-quotes.
To adhere to the repository style guide's philosophy of "Optimize for readability", we should use a consistent and cleaner string quoting style. Since the string contains single quotes (Can't), we can use double quotes for the first segment and single quotes for the rest, avoiding any triple-quotes or unnecessary escaping.
| throw ArgumentError.value( | |
| fileSystem, | |
| 'fileSystem', | |
| '''Can't list using glob \"$this\"; it matches ''' | |
| '${context.style} paths, but the file system uses ' | |
| '${fileSystem.path.style} paths.'); | |
| throw ArgumentError.value( | |
| fileSystem, | |
| 'fileSystem', | |
| "Can't list using glob \"$this\"; it matches " | |
| '${context.style} paths, but the file system uses ' | |
| '${fileSystem.path.style} paths.'); |
References
- Optimize for readability - code is read more often than it is written. (link)
| if (fileSystem.path.style == p.windows.style) | ||
| text.replaceAll('/', r'\'); |
There was a problem hiding this comment.
| if (fileSystem.path.style == p.windows.style) | |
| text.replaceAll('/', r'\'); |
This was always a no-op, and always unnecessary. This replacement wouldn't impact p.isAbsolute result.
|
This fixes the guard and the split, but the node listing methods still use the platform context: Also Happy to send a follow-up for the node methods once this lands, or fold it in here if you prefer. |
Fixes #1998
Makes the
ListTreeclass use thefileSystem.pathpath context instead of the platform context,p.contextofpackage:path.Calls to
ListTreechecks that the glob's path context and the file system's path context are the same style.