Skip to content

fix: handle paths with escaped spaces in Cargo dep-info files - #121

Open
AnisHerdev wants to merge 1 commit into
GregoryConrad:mainfrom
AnisHerdev:fix/dep-info-spaces
Open

AnisHerdev wants to merge 1 commit into
GregoryConrad:mainfrom
AnisHerdev:fix/dep-info-spaces

Conversation

@AnisHerdev

Copy link
Copy Markdown

Summary

Fixes DependencyDiscoverer.discover when source file paths listed in Cargo .d dep-info files contain spaces (e.g. Windows user profile directories like C:\Users\John Doe\... or project paths containing spaces).

Root Cause

Cargo and rustc emit Makefile-compatible dep-info files where spaces within prerequisite paths are escaped using backslashes (\ ).

The previous implementation:

return File(dependencyFilePath)
    .readAsLinesSync()
    .expand((line) => line.trim().split(' ').skip(1))
    .map(path.toUri);

performed a naive .split(' '). For paths containing spaces (e.g. C:\Users\John\ Doe\lib.rs), this broke the single file path into invalid tokens:

  • C:\Users\John\
  • Doe\lib.rs

When these broken tokens are forwarded to Flutter's native assets hook runner (build_hooks), Flutter treats path tokens ending in separators as directories to watch and attempts directory listing on C:\Users\John\*, crashing the entire build with:

Target build_hooks failed: FileSystemException: Directory listing failed, path = 'C:\Users\John\*' (OS Error: The directory name is invalid, errno = 267)

Solution

  1. Normalize Line Continuations: Replaces Make-style line continuations (\ followed by a newline) so multi-line prerequisite rules parse cleanly.
  2. Preserve Escaped Spaces: Splits prerequisites using a negative lookbehind regex (?<!\\) +, ensuring that escaped spaces (\ ) inside file paths are not treated as token delimiters.
  3. Unescape Prerequisite Paths: Replaces \ with standard spaces before passing each token to path.toUri.
  4. Unit Tests: Added test cases in dependency_discoverer_test.dart testing escaped spaces on Windows and POSIX paths, as well as line continuations.

Verification

  • dart analyze: 0 issues found (passed very_good_analysis).
  • dart format: Fully formatted.
  • dart test test/dependency_discoverer_test.dart: All 6 tests passed.

Cargo and rustc emit Makefile-compatible dep-info (.d) files where spaces within paths are escaped with backslashes (\\ \). Previously, \DependencyDiscoverer\ used \line.trim().split(' ').skip(1)\, which erroneously split paths containing spaces (such as Windows user profiles or folders with spaces) into separate invalid tokens. This caused Flutter's native assets hook runner to fail with a directory listing error when watching dependencies.

This change:
- Unescapes Make-style escaped spaces (\\ \ -> space) while splitting dependencies only on unescaped whitespace.
- Normalizes Make-style line continuations (\\\\ followed by a newline).
- Adds unit test coverage for escaped spaces and line continuations.
@AnisHerdev

Copy link
Copy Markdown
Author

Note on CI Integration Test Failures

The core build_and_test job passed completely (Rust clippy/fmt/tests, Dart analyze/format, and package unit tests all succeeded).

The failures across the 5 integration test jobs (macos, windows, linux, ios, and android) are unrelated to this PR's changes. All 5 runners failed before test execution during melos run init-integration-test-boilerplate with:

ERROR: Unhandled exception:
Bad state: Could not find global installation of melos:melos.
Platform.script: file:///.../.pub-cache/hosted/pub.dev/melos-8.10.1/bin/melos.dart
Platform.resolvedExecutable: .../dart
This is likely a bug in `package:cli_launcher`.
#0      _findGlobalInstallation (package:cli_launcher/cli_launcher.dart:408:5)
#1      _launchFromGlobalInstallation (package:cli_launcher/cli_launcher.dart:853:30)
#2      launchExecutable (package:cli_launcher/cli_launcher.dart:842:11)
#3      main (file:///.../.pub-cache/hosted/pub.dev/melos-8.10.1/bin/melos.dart:5:52)

Root cause:

  • .github/workflows/build.yml uses subosito/flutter-action@v2 without pinning a version, pulling the latest stable release.
  • On November 10, Flutter 3.50.0 (with Dart 3.14.0) was released.
  • Under Flutter 3.50.0 / Dart 3.14.0, executing init-integration-test-boilerplate (which delegates to nested dart run melos:melos exec ... because melos is a workspace dev_dependency) runs directly from the hosted package cache path (.pub-cache/hosted/...). This path is not recognized as a global installation by package:cli_launcher, throwing an unhandled StateError.
  • This same failure reproduces across all concurrent PRs on this repo (e.g. Honor the Android API requested by Rust build hooks #122).

I have intentionally kept this PR strictly scoped to the Cargo dep-info escaped spaces fix without altering workflow files. If helpful, I would be happy to open a separate PR to address the CI runner compatibility (e.g. pinning Flutter or adjusting the Melos script invocation).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants